haitask 0.1.6 → 0.3.3

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/.env.example CHANGED
@@ -1,24 +1,27 @@
1
- # HAITASK — copy to .env and fill in
2
- # Set only the key for the provider you use in .haitaskrc (ai.provider)
3
-
4
- # Groq (FREE, fast): https://console.groq.com/keys
5
- GROQ_API_KEY=your-groq-api-key
6
-
7
- # Deepseek (FREE): https://platform.deepseek.com/
8
- DEEPSEEK_API_KEY=your-deepseek-api-key
9
-
10
- # OpenAI (paid): https://platform.openai.com/api-keys
11
- OPENAI_API_KEY=your-openai-api-key
12
-
13
- # Jira (required for creating issues)
14
- JIRA_BASE_URL=https://your-domain.atlassian.net
15
- JIRA_EMAIL=your@email.com
16
- JIRA_API_TOKEN=your-jira-api-token
17
- # Optional: assign new issues to you. Jira Cloud account ID: Profile → Account ID, or admin.atlassian.com → Directory → Users. If value contains ":", use quotes: JIRA_ACCOUNT_ID="id:uuid"
18
- JIRA_ACCOUNT_ID=your-account-id
19
-
20
- # Trello (when target is trello in .haitaskrc). Get key + token: https://trello.com/app-key
21
- TRELLO_API_KEY=your-trello-api-key
22
- TRELLO_TOKEN=your-trello-token
23
- # Optional: assign new cards to you (Trello member ID)
24
- TRELLO_MEMBER_ID=your-member-id
1
+ # HAITASK — copy to .env and fill in
2
+ # Set only the key for the provider you use in .haitaskrc (ai.provider)
3
+
4
+ # Groq (FREE, fast): https://console.groq.com/keys
5
+ GROQ_API_KEY=your-groq-api-key
6
+
7
+ # Deepseek (FREE): https://platform.deepseek.com/
8
+ DEEPSEEK_API_KEY=your-deepseek-api-key
9
+
10
+ # OpenAI (paid): https://platform.openai.com/api-keys
11
+ OPENAI_API_KEY=your-openai-api-key
12
+
13
+ # Jira (required for creating issues)
14
+ JIRA_BASE_URL=https://your-domain.atlassian.net
15
+ JIRA_EMAIL=your@email.com
16
+ JIRA_API_TOKEN=your-jira-api-token
17
+ # Optional: assign new issues to you. Jira Cloud account ID: Profile → Account ID, or admin.atlassian.com → Directory → Users. If value contains ":", use quotes: JIRA_ACCOUNT_ID="id:uuid"
18
+ JIRA_ACCOUNT_ID=your-account-id
19
+
20
+ # Trello (when target is trello in .haitaskrc). Get key + token: https://trello.com/app-key
21
+ TRELLO_API_KEY=your-trello-api-key
22
+ TRELLO_TOKEN=your-trello-token
23
+ # Optional: assign new cards to you (Trello member ID)
24
+ TRELLO_MEMBER_ID=your-member-id
25
+
26
+ # Linear (when target is linear in .haitaskrc). Get key: https://linear.app/settings/api
27
+ LINEAR_API_KEY=your-linear-api-key
package/README.md CHANGED
@@ -1,100 +1,119 @@
1
- # HAITASK
2
-
3
- Generate tasks from your latest Git commit using AI in **Jira** or **Trello**. Reads commit message and branch, produces a structured task (title, description, labels) via an AI provider, and creates the issue/card in your chosen target. Framework- and language-agnostic: works with any Git repo.
4
-
5
- **Requirements:** Node.js >= 18
6
-
7
- ---
8
-
9
- ## Install
10
-
11
- ```bash
12
- npm install -g haitask
13
- ```
14
-
15
- Or run without installing:
16
-
17
- ```bash
18
- npx haitask
19
- ```
20
-
21
- From source (clone then link):
22
-
23
- ```bash
24
- git clone https://github.com/HidayetHidayetov/haitask.git && cd haitask && npm install && npm link
25
- ```
26
-
27
- ---
28
-
29
- ## Quick start
30
-
31
- 1. **Per project (one-time)**
32
- In the Git repo where you want to create tasks:
33
- ```bash
34
- cd /path/to/your/repo
35
- haitask init
36
- ```
37
- **Interactive setup:** choose **target** (1 = Jira, 2 = Trello), then target-specific options (Jira: base URL, project key, issue type, status; Trello: list ID, optional label IDs, member ID). You’ll also set AI provider (groq / deepseek / openai), allowed branches, and commit prefixes. A `.haitaskrc` file is created. Choose where to store API keys: **this project** (`.env`) or **global** (`~/.haitask/.env`). A template `.env` is created — add your keys there (never commit real keys).
38
-
39
- 2. **Add your API keys**
40
- Edit the `.env` that was created:
41
- - **AI:** one of `GROQ_API_KEY`, `DEEPSEEK_API_KEY`, `OPENAI_API_KEY`.
42
- - **Jira** (when target is jira): `JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN`. Optional: `JIRA_ACCOUNT_ID`.
43
- - **Trello** (when target is trello): `TRELLO_API_KEY`, `TRELLO_TOKEN`. Optional: `TRELLO_MEMBER_ID`. Get key + token at https://trello.com/app-key.
44
-
45
- 3. **Create a task from the latest commit**
46
- After committing:
47
- ```bash
48
- haitask run
49
- ```
50
- Pipeline: read latest commit → validate branch/prefix → call AI → create task in Jira or Trello.
51
- To test without creating: `haitask run --dry`.
52
-
53
- ---
54
-
55
- ## Commands
56
-
57
- | Command | Description |
58
- |--------|-------------|
59
- | `haitask init` | Interactive setup: target (Jira/Trello), then target + AI + rules → writes `.haitaskrc`, optional `.env`. |
60
- | `haitask run` | Run pipeline: Git → AI → target (create Jira issue or Trello card). |
61
- | `haitask run --dry` | Same as above but skips creating the task. |
62
- | `haitask run --type <type>` | (Jira only) Override issue type for this run (e.g. `Task`, `Bug`, `Story`). |
63
- | `haitask run --status <status>` | (Jira only) Override transition-to status after create (e.g. `Done`, `To Do`, `In Progress`). |
64
-
65
- ---
66
-
67
- ## Configuration
68
-
69
- - **`.haitaskrc`** (project root): **`target`** (`jira` or `trello`); target-specific section (`jira` or `trello`); **`ai`** (`provider`, `model`); **`rules`** (`allowedBranches`, `commitPrefixes`). Single source of truth.
70
- - **`.env`**: API keys only. Loaded: **project** `.env`, then **global** `~/.haitask/.env`.
71
-
72
- **Target: Jira** — `jira.baseUrl`, `jira.projectKey`, `jira.issueType`, `jira.transitionToStatus`. Override issue type/status for one run: `haitask run --type Bug`, `haitask run --status "To Do"`. Optional assignee: `JIRA_ACCOUNT_ID` in `.env` (Jira Cloud account ID; use quotes if value contains `:`).
73
-
74
- **Target: Trello** — `trello.listId` (required: the list where new cards go; get from board URL or API). Optional: `trello.labelIds` (array of label IDs), `trello.memberId` or `TRELLO_MEMBER_ID` in `.env` for assignee. Get API key + token at https://trello.com/app-key.
75
-
76
- **AI providers** (`ai.provider`): `groq` (default, free), `deepseek` (free), `openai` (paid). Set the matching key in `.env`.
77
-
78
- **Rules:** If `allowedBranches` is non-empty, the current branch must be in the list. If `commitPrefixes` is non-empty, the commit message must start with one of them (e.g. `feat:`, `fix:`).
79
-
80
- **Task title:** The AI is instructed not to include commit-type prefixes (e.g. `feat:`) in the task title; the code strips them so the summary stays clean.
81
-
82
- ---
83
-
84
- ## Usage patterns
85
-
86
- - **Global install:** `npm install -g haitask` → in any repo: `haitask init` once, then `haitask run` after commits.
87
- - **Per-project dev dependency:** `npm install haitask --save-dev` `npx haitask run`.
88
- - **CI / scripts:** Run `npx haitask run` (or `haitask run` if installed) from the repo root; ensure `.haitaskrc` and env vars are available in that environment.
89
-
90
- No framework-specific setup (e.g. Laravel, React, etc.); the tool only depends on Git and the config files above.
91
-
92
- ---
93
-
94
- ## Troubleshooting
95
-
96
- **Jira assignee not set / still unassigned**
97
- In Jira Cloud, the user in `JIRA_ACCOUNT_ID` must be an **Assignable user** in that project. Fix: **Project → Space settings → People** — add yourself (team-managed). For company-managed projects, ensure the permission scheme grants **Assignable user**. You can still assign manually in Jira.
98
-
99
- **Trello — list ID**
100
- List ID is the ID of the list (column) where new cards are created. In Trello: open the board, click the list menu (⋯), “Copy list link” or “Copy link” — the URL contains the list ID. Or use the API: `GET https://api.trello.com/1/boards/{boardId}/lists?key=...&token=...` to list all list IDs.
1
+ # HAITASK
2
+
3
+ > Turn a Git commit into a task in Jira, Trello, or Linear one command.
4
+
5
+ HAITASK reads your latest commit message and branch, uses AI to shape a clear title and description, and creates the issue or card in the tool you use. No framework lock-in: works in any Git repo.
6
+
7
+ **Requires:** Node.js 18+
8
+
9
+ ---
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install -g haitask
15
+ ```
16
+
17
+ Run without installing:
18
+
19
+ ```bash
20
+ npx haitask
21
+ ```
22
+
23
+ ---
24
+
25
+ ## Quick start
26
+
27
+ **1. Configure (once)**
28
+ In your project root:
29
+
30
+ ```bash
31
+ haitask init
32
+ ```
33
+
34
+ Pick a target (1 = Jira, 2 = Trello, 3 = Linear) and answer the prompts. You get a `.haitaskrc` and an optional `.env` template.
35
+ **Quick mode:** `haitask init --quick` — fewer questions, sensible defaults.
36
+
37
+ **2. Add API keys**
38
+ In the generated `.env`, set the keys for your target and AI provider:
39
+
40
+ | Target | Keys |
41
+ |---------|------|
42
+ | **Jira** | `JIRA_BASE_URL`, `JIRA_EMAIL`, `JIRA_API_TOKEN` [Atlassian API tokens](https://id.atlassian.com/manage-profile/security/api-tokens) |
43
+ | **Trello** | `TRELLO_API_KEY`, `TRELLO_TOKEN` [trello.com/app-key](https://trello.com/app-key) |
44
+ | **Linear** | `LINEAR_API_KEY` — [linear.app/settings/api](https://linear.app/settings/api) |
45
+
46
+ For AI, set one of: `GROQ_API_KEY`, `DEEPSEEK_API_KEY`, or `OPENAI_API_KEY` (default is Groq).
47
+
48
+ **3. Create a task**
49
+ After you commit:
50
+
51
+ ```bash
52
+ haitask run
53
+ ```
54
+
55
+ To try without creating a task: `haitask run --dry`.
56
+
57
+ ---
58
+
59
+ ## Commands
60
+
61
+ | Command | Description |
62
+ |---------|-------------|
63
+ | `haitask init` | Interactive setup: target, AI, rules writes `.haitaskrc` and optional `.env` |
64
+ | `haitask init --quick` | Minimal prompts: target + required fields only; defaults for AI, branches, prefixes |
65
+ | `haitask check` | Validate `.haitaskrc` + required env keys without running the pipeline |
66
+ | `haitask run` | Creates a task from the latest commit (Jira / Trello / Linear) |
67
+ | `haitask run --dry` | Same flow, but does not create a task |
68
+ | `haitask run --commits N` | Combine the last N commits into one task (e.g. `--commits 3`) |
69
+ | `haitask run --type <type>` | (Jira only) Override issue type for this run (Task, Bug, Story) |
70
+ | `haitask run --status <status>` | (Jira only) Override status after create (Done, "To Do", etc.) |
71
+
72
+ ---
73
+
74
+ ## Configuration
75
+
76
+ - **`.haitaskrc`** `target` (jira / trello / linear), target-specific options, `ai` (provider, model), `rules` (allowedBranches, commitPrefixes).
77
+ - **`.env`** — API keys only. Load order: project `.env` then `~/.haitask/.env`.
78
+
79
+ **Security:** Keys live only in `.env` (do not commit it). They are sent only to the services you use: your target (Jira/Trello/Linear) and your chosen AI provider.
80
+
81
+ **Jira:** `jira.baseUrl`, `jira.projectKey`, `jira.issueType`, `jira.transitionToStatus`. Optional assignee: `JIRA_ACCOUNT_ID` in `.env`.
82
+
83
+ **Trello:** `trello.listId` (required — the list where new cards go). To get the list ID: open the board → **⋯** on the list header → “Copy list link” → the 24-character ID is in the URL. From the haitask repo you can run `node scripts/get-trello-list.js` (with Trello keys in `.env`) to print the first list ID.
84
+
85
+ **Linear:** `linear.teamId` (required). In Linear: Team → Settings → copy Team ID.
86
+
87
+ **AI:** `groq` (free), `deepseek` (free), `openai` (paid). Set the matching key in `.env`.
88
+
89
+ **Rules:** If `allowedBranches` or `commitPrefixes` are set, the current branch and commit message are checked. If the commit message contains an issue key (e.g. `PROJ-123`, `ENG-42`), haitask adds a comment to that issue instead of creating a new task; set `rules.linkToExistingIssue: false` in `.haitaskrc` to always create new tasks.
90
+
91
+ ---
92
+
93
+ ## Usage
94
+
95
+ - **Global:** `npm install -g haitask` → run `haitask init` once per repo, then `haitask run` after commits.
96
+ - **Per project:** `npm install haitask --save-dev` `npx haitask run`.
97
+ - **CI / scripts:** Run `npx haitask run` from the repo root; ensure `.haitaskrc` and env vars are available.
98
+
99
+ ---
100
+
101
+ ## Roadmap
102
+
103
+ - ✅ **Batch** — `haitask run --commits N`
104
+ - ✅ **Link to existing issue** — commit message with issue key (e.g. PROJ-123) → comment on that issue
105
+ - ✅ **Linear** — target `linear`, `linear.teamId`, `LINEAR_API_KEY`
106
+ - 🔜 More targets (same adapter pattern)
107
+
108
+ ---
109
+
110
+ ## Troubleshooting
111
+
112
+ **Jira — assignee not set**
113
+ The user in `JIRA_ACCOUNT_ID` must be an assignable user in that project. In Jira: Project → Space settings → People, or assign manually.
114
+
115
+ **Trello — list ID**
116
+ You need the 24-character hex list ID. Open the board → **⋯** on the list → “Copy list link” → use the ID from the URL as `trello.listId`. Or run `node scripts/get-trello-list.js` from the haitask repo (Trello keys in `.env`).
117
+
118
+ **Linear — team ID or API key**
119
+ Copy Team ID from Linear → Team → Settings. Create an API key at [linear.app/settings/api](https://linear.app/settings/api) and set `LINEAR_API_KEY` in `.env`.
package/package.json CHANGED
@@ -1,44 +1,47 @@
1
- {
2
- "name": "haitask",
3
- "version": "0.1.6",
4
- "description": "HAITASK — AI-powered task creation from Git commits. Creates issues in Jira or Trello from your latest commit message and branch.",
5
- "type": "module",
6
- "main": "src/index.js",
7
- "bin": {
8
- "haitask": "src/index.js"
9
- },
10
- "engines": {
11
- "node": ">=18"
12
- },
13
- "files": [
14
- "src",
15
- "README.md",
16
- ".env.example"
17
- ],
18
- "scripts": {
19
- "start": "node src/index.js",
20
- "init": "node src/index.js init",
21
- "run": "node src/index.js run"
22
- },
23
- "keywords": [
24
- "cli",
25
- "jira",
26
- "git",
27
- "ai",
28
- "automation",
29
- "commit",
30
- "task"
31
- ],
32
- "license": "MIT",
33
- "repository": {
34
- "type": "git",
35
- "url": "git+https://github.com/HidayetHidayetov/haitask.git"
36
- },
37
- "homepage": "https://github.com/HidayetHidayetov/haitask#readme",
38
- "bugs": "https://github.com/HidayetHidayetov/haitask/issues",
39
- "dependencies": {
40
- "commander": "^12.0.0",
41
- "dotenv": "^16.4.5",
42
- "execa": "^9.5.2"
43
- }
44
- }
1
+ {
2
+ "name": "haitask",
3
+ "version": "0.3.3",
4
+ "description": "HAITASK — AI-powered task creation from Git commits. Creates issues in Jira, Trello, or Linear from your latest commit message and branch.",
5
+ "type": "module",
6
+ "main": "src/index.js",
7
+ "bin": {
8
+ "haitask": "src/index.js"
9
+ },
10
+ "engines": {
11
+ "node": ">=18"
12
+ },
13
+ "files": [
14
+ "src",
15
+ "README.md",
16
+ ".env.example"
17
+ ],
18
+ "scripts": {
19
+ "start": "node src/index.js",
20
+ "init": "node src/index.js init",
21
+ "run": "node src/index.js run",
22
+ "test": "node --test test/*.test.js"
23
+ },
24
+ "keywords": [
25
+ "cli",
26
+ "jira",
27
+ "trello",
28
+ "linear",
29
+ "git",
30
+ "ai",
31
+ "automation",
32
+ "commit",
33
+ "task"
34
+ ],
35
+ "license": "MIT",
36
+ "repository": {
37
+ "type": "git",
38
+ "url": "git+https://github.com/HidayetHidayetov/haitask.git"
39
+ },
40
+ "homepage": "https://github.com/HidayetHidayetov/haitask#readme",
41
+ "bugs": "https://github.com/HidayetHidayetov/haitask/issues",
42
+ "dependencies": {
43
+ "commander": "^12.0.0",
44
+ "dotenv": "^16.4.5",
45
+ "execa": "^9.5.2"
46
+ }
47
+ }
@@ -1,54 +1,54 @@
1
- /**
2
- * Deepseek Chat provider (free tier, JSON mode supported).
3
- * API: https://api.deepseek.com/v1/chat/completions
4
- * Docs: https://platform.deepseek.com/api-docs/
5
- */
6
-
7
- import { buildPrompt, parseTaskPayload } from './utils.js';
8
-
9
- const DEEPSEEK_API_URL = 'https://api.deepseek.com/v1/chat/completions';
10
-
11
- /**
12
- * Call Deepseek and return task payload for Jira.
13
- * @param {{ message: string, branch: string, repoName: string }} commitData
14
- * @param {{ ai: { model?: string } }} config
15
- * @returns {Promise<{ title: string, description: string, labels: string[] }>}
16
- */
17
- export async function generateDeepseek(commitData, config) {
18
- const apiKey = process.env.DEEPSEEK_API_KEY;
19
- if (!apiKey?.trim()) {
20
- throw new Error('DEEPSEEK_API_KEY is not set. Add it to .env. Get free key at https://platform.deepseek.com/');
21
- }
22
-
23
- const model = config?.ai?.model || 'deepseek-chat';
24
- const { system, user } = buildPrompt(commitData);
25
-
26
- const response = await fetch(DEEPSEEK_API_URL, {
27
- method: 'POST',
28
- headers: {
29
- 'Content-Type': 'application/json',
30
- Authorization: `Bearer ${apiKey}`,
31
- },
32
- body: JSON.stringify({
33
- model,
34
- messages: [
35
- { role: 'system', content: system },
36
- { role: 'user', content: user },
37
- ],
38
- response_format: { type: 'json_object' },
39
- }),
40
- });
41
-
42
- if (!response.ok) {
43
- const body = await response.text();
44
- throw new Error(`Deepseek API error ${response.status}: ${body || response.statusText}`);
45
- }
46
-
47
- const data = await response.json();
48
- const content = data?.choices?.[0]?.message?.content;
49
- if (typeof content !== 'string') {
50
- throw new Error('Deepseek response missing choices[0].message.content');
51
- }
52
-
53
- return parseTaskPayload(content.trim());
54
- }
1
+ /**
2
+ * Deepseek Chat provider (free tier, JSON mode supported).
3
+ * API: https://api.deepseek.com/v1/chat/completions
4
+ * Docs: https://platform.deepseek.com/api-docs/
5
+ */
6
+
7
+ import { buildPrompt, parseTaskPayload } from './utils.js';
8
+
9
+ const DEEPSEEK_API_URL = 'https://api.deepseek.com/v1/chat/completions';
10
+
11
+ /**
12
+ * Call Deepseek and return task payload for Jira.
13
+ * @param {{ message: string, branch: string, repoName: string }} commitData
14
+ * @param {{ ai: { model?: string } }} config
15
+ * @returns {Promise<{ title: string, description: string, labels: string[] }>}
16
+ */
17
+ export async function generateDeepseek(commitData, config) {
18
+ const apiKey = process.env.DEEPSEEK_API_KEY;
19
+ if (!apiKey?.trim()) {
20
+ throw new Error('DEEPSEEK_API_KEY is not set. Add it to .env. Get free key at https://platform.deepseek.com/');
21
+ }
22
+
23
+ const model = config?.ai?.model || 'deepseek-chat';
24
+ const { system, user } = buildPrompt(commitData);
25
+
26
+ const response = await fetch(DEEPSEEK_API_URL, {
27
+ method: 'POST',
28
+ headers: {
29
+ 'Content-Type': 'application/json',
30
+ Authorization: `Bearer ${apiKey}`,
31
+ },
32
+ body: JSON.stringify({
33
+ model,
34
+ messages: [
35
+ { role: 'system', content: system },
36
+ { role: 'user', content: user },
37
+ ],
38
+ response_format: { type: 'json_object' },
39
+ }),
40
+ });
41
+
42
+ if (!response.ok) {
43
+ const body = await response.text();
44
+ throw new Error(`Deepseek API error ${response.status}: ${body || response.statusText}`);
45
+ }
46
+
47
+ const data = await response.json();
48
+ const content = data?.choices?.[0]?.message?.content;
49
+ if (typeof content !== 'string') {
50
+ throw new Error('Deepseek response missing choices[0].message.content');
51
+ }
52
+
53
+ return parseTaskPayload(content.trim());
54
+ }
package/src/ai/groq.js CHANGED
@@ -1,56 +1,56 @@
1
- /**
2
- * Groq provider (free tier, fast inference).
3
- * API: https://api.groq.com/openai/v1/chat/completions (OpenAI-compatible)
4
- * Docs: https://console.groq.com/docs
5
- */
6
-
7
- import { buildPrompt, parseTaskPayload } from './utils.js';
8
-
9
- const GROQ_API_URL = 'https://api.groq.com/openai/v1/chat/completions';
10
-
11
- /**
12
- * Call Groq and return task payload for Jira.
13
- * @param {{ message: string, branch: string, repoName: string }} commitData
14
- * @param {{ ai: { model?: string } }} config
15
- * @returns {Promise<{ title: string, description: string, labels: string[] }>}
16
- */
17
- export async function generateGroq(commitData, config) {
18
- const apiKey = process.env.GROQ_API_KEY;
19
- if (!apiKey?.trim()) {
20
- throw new Error(
21
- 'GROQ_API_KEY is not set. Add it to .env. Get free key at https://console.groq.com/keys'
22
- );
23
- }
24
-
25
- const model = config?.ai?.model || 'llama-3.1-8b-instant';
26
- const { system, user } = buildPrompt(commitData);
27
-
28
- const response = await fetch(GROQ_API_URL, {
29
- method: 'POST',
30
- headers: {
31
- 'Content-Type': 'application/json',
32
- Authorization: `Bearer ${apiKey}`,
33
- },
34
- body: JSON.stringify({
35
- model,
36
- messages: [
37
- { role: 'system', content: system },
38
- { role: 'user', content: user },
39
- ],
40
- response_format: { type: 'json_object' },
41
- }),
42
- });
43
-
44
- if (!response.ok) {
45
- const body = await response.text();
46
- throw new Error(`Groq API error ${response.status}: ${body || response.statusText}`);
47
- }
48
-
49
- const data = await response.json();
50
- const content = data?.choices?.[0]?.message?.content;
51
- if (typeof content !== 'string') {
52
- throw new Error('Groq response missing choices[0].message.content');
53
- }
54
-
55
- return parseTaskPayload(content.trim());
56
- }
1
+ /**
2
+ * Groq provider (free tier, fast inference).
3
+ * API: https://api.groq.com/openai/v1/chat/completions (OpenAI-compatible)
4
+ * Docs: https://console.groq.com/docs
5
+ */
6
+
7
+ import { buildPrompt, parseTaskPayload } from './utils.js';
8
+
9
+ const GROQ_API_URL = 'https://api.groq.com/openai/v1/chat/completions';
10
+
11
+ /**
12
+ * Call Groq and return task payload for Jira.
13
+ * @param {{ message: string, branch: string, repoName: string }} commitData
14
+ * @param {{ ai: { model?: string } }} config
15
+ * @returns {Promise<{ title: string, description: string, labels: string[] }>}
16
+ */
17
+ export async function generateGroq(commitData, config) {
18
+ const apiKey = process.env.GROQ_API_KEY;
19
+ if (!apiKey?.trim()) {
20
+ throw new Error(
21
+ 'GROQ_API_KEY is not set. Add it to .env. Get free key at https://console.groq.com/keys'
22
+ );
23
+ }
24
+
25
+ const model = config?.ai?.model || 'llama-3.1-8b-instant';
26
+ const { system, user } = buildPrompt(commitData);
27
+
28
+ const response = await fetch(GROQ_API_URL, {
29
+ method: 'POST',
30
+ headers: {
31
+ 'Content-Type': 'application/json',
32
+ Authorization: `Bearer ${apiKey}`,
33
+ },
34
+ body: JSON.stringify({
35
+ model,
36
+ messages: [
37
+ { role: 'system', content: system },
38
+ { role: 'user', content: user },
39
+ ],
40
+ response_format: { type: 'json_object' },
41
+ }),
42
+ });
43
+
44
+ if (!response.ok) {
45
+ const body = await response.text();
46
+ throw new Error(`Groq API error ${response.status}: ${body || response.statusText}`);
47
+ }
48
+
49
+ const data = await response.json();
50
+ const content = data?.choices?.[0]?.message?.content;
51
+ if (typeof content !== 'string') {
52
+ throw new Error('Groq response missing choices[0].message.content');
53
+ }
54
+
55
+ return parseTaskPayload(content.trim());
56
+ }