jira-ai 1.1.0 → 1.2.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.
- package/README.md +37 -0
- package/dist/cli.js +10 -4
- package/dist/commands/run-jql.js +26 -2
- package/dist/lib/settings.js +10 -0
- package/dist/lib/validation.js +4 -0
- package/package.json +1 -1
- package/settings.yaml +9 -0
package/README.md
CHANGED
|
@@ -191,6 +191,43 @@ When `authType` is set to `service_account`, jira-ai automatically:
|
|
|
191
191
|
|
|
192
192
|
Existing configurations using standard API tokens are unaffected.
|
|
193
193
|
|
|
194
|
+
## Saved Queries
|
|
195
|
+
|
|
196
|
+
Define reusable JQL queries in your `settings.yaml` under the `saved-queries` key to avoid repeating common searches.
|
|
197
|
+
|
|
198
|
+
### Configuration
|
|
199
|
+
|
|
200
|
+
Add a `saved-queries` map to your `settings.yaml` — each key is a query name (lowercase alphanumeric with hyphens) and each value is a JQL string:
|
|
201
|
+
|
|
202
|
+
```yaml
|
|
203
|
+
saved-queries:
|
|
204
|
+
my-open-bugs: "project = PROJ AND status = Open AND issuetype = Bug"
|
|
205
|
+
overdue-tasks: "project = PROJ AND duedate < now() AND status != Done"
|
|
206
|
+
my-assignee: "assignee = currentUser()"
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
### Usage
|
|
210
|
+
|
|
211
|
+
Run a saved query by name:
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
jira-ai issue search --query my-open-bugs
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
List all configured saved queries:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
jira-ai issue search --list-queries
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
Combine with result limits:
|
|
224
|
+
|
|
225
|
+
```bash
|
|
226
|
+
jira-ai issue search --query overdue-tasks --limit 10
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
Saved queries are mutually exclusive with raw JQL — you cannot provide both a positional JQL argument and `--query` at the same time.
|
|
230
|
+
|
|
194
231
|
## Configuration & Restrictions
|
|
195
232
|
|
|
196
233
|
Tool allows you to have very complex configutations of what Projects/Jira commands/Issue types you would have acess to thought the tool.
|
package/dist/cli.js
CHANGED
|
@@ -131,14 +131,20 @@ issue
|
|
|
131
131
|
.option('--custom-field <field=value>', 'Custom field in fieldId=value format (repeatable)', (val, prev) => [...(prev || []), val], [])
|
|
132
132
|
.action(withPermission('issue.create', createTaskCommand, { schema: CreateTaskSchema }));
|
|
133
133
|
issue
|
|
134
|
-
.command('search
|
|
135
|
-
.description('Execute a JQL search query.
|
|
134
|
+
.command('search [jql-query]')
|
|
135
|
+
.description('Execute a JQL search query. Provide raw JQL or use --query to reference a saved query.')
|
|
136
136
|
.option('-l, --limit <number>', 'Maximum number of results (default: 50)', '50')
|
|
137
|
+
.option('--query <name>', 'Use a saved query by name (mutually exclusive with positional JQL)')
|
|
138
|
+
.option('--list-queries', 'List all available saved queries')
|
|
137
139
|
.action(withPermission('issue.search', runJqlCommand, {
|
|
138
140
|
schema: RunJqlSchema,
|
|
139
141
|
validateArgs: (args) => {
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
const jqlQuery = args[0];
|
|
143
|
+
const opts = args[args.length - 2];
|
|
144
|
+
const hasQuery = opts && opts.query;
|
|
145
|
+
const hasListQueries = opts && opts.listQueries;
|
|
146
|
+
if (!hasQuery && !hasListQueries && (typeof jqlQuery !== 'string' || jqlQuery.trim() === '')) {
|
|
147
|
+
throw new CliError('JQL query cannot be empty. Provide a JQL query, use --query <name>, or use --list-queries.');
|
|
142
148
|
}
|
|
143
149
|
}
|
|
144
150
|
}));
|
package/dist/commands/run-jql.js
CHANGED
|
@@ -1,11 +1,35 @@
|
|
|
1
1
|
import { searchIssuesByJql } from '../lib/jira-client.js';
|
|
2
2
|
import { outputResult } from '../lib/json-mode.js';
|
|
3
|
+
import { getSavedQuery, listSavedQueries } from '../lib/settings.js';
|
|
4
|
+
import { CliError } from '../types/errors.js';
|
|
3
5
|
export async function runJqlCommand(jqlQuery, options) {
|
|
4
|
-
//
|
|
6
|
+
// Handle --list-queries
|
|
7
|
+
if (options.listQueries) {
|
|
8
|
+
const queries = listSavedQueries();
|
|
9
|
+
outputResult({ queries });
|
|
10
|
+
return;
|
|
11
|
+
}
|
|
12
|
+
// Mutual exclusion: can't have both positional JQL and --query
|
|
13
|
+
if (jqlQuery && jqlQuery.trim() !== '' && options.query) {
|
|
14
|
+
throw new CliError('Cannot specify both JQL query and --query. Use one or the other.');
|
|
15
|
+
}
|
|
16
|
+
let resolvedJql;
|
|
17
|
+
if (options.query) {
|
|
18
|
+
const savedJql = getSavedQuery(options.query);
|
|
19
|
+
if (savedJql === undefined) {
|
|
20
|
+
const available = listSavedQueries().map((q) => q.name).join(', ');
|
|
21
|
+
const availableMsg = available ? available : '(none)';
|
|
22
|
+
throw new CliError(`Saved query '${options.query}' not found. Available: ${availableMsg}`);
|
|
23
|
+
}
|
|
24
|
+
resolvedJql = savedJql;
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
resolvedJql = jqlQuery;
|
|
28
|
+
}
|
|
5
29
|
let maxResults = options.limit || 50;
|
|
6
30
|
if (maxResults > 1000) {
|
|
7
31
|
maxResults = 1000;
|
|
8
32
|
}
|
|
9
|
-
const issues = await searchIssuesByJql(
|
|
33
|
+
const issues = await searchIssuesByJql(resolvedJql, maxResults);
|
|
10
34
|
outputResult(issues);
|
|
11
35
|
}
|
package/dist/lib/settings.js
CHANGED
|
@@ -4,6 +4,16 @@ import os from 'os';
|
|
|
4
4
|
import yaml from 'js-yaml';
|
|
5
5
|
import { CliError } from '../types/errors.js';
|
|
6
6
|
import { SettingsSchema } from './validation.js';
|
|
7
|
+
export function getSavedQuery(name) {
|
|
8
|
+
const settings = loadSettings();
|
|
9
|
+
return settings.savedQueries?.[name];
|
|
10
|
+
}
|
|
11
|
+
export function listSavedQueries() {
|
|
12
|
+
const settings = loadSettings();
|
|
13
|
+
if (!settings.savedQueries)
|
|
14
|
+
return [];
|
|
15
|
+
return Object.entries(settings.savedQueries).map(([name, jql]) => ({ name, jql }));
|
|
16
|
+
}
|
|
7
17
|
// Mapping from old flat command names to new hierarchical paths
|
|
8
18
|
export const LEGACY_COMMAND_MAP = {
|
|
9
19
|
'me': 'user.me',
|
package/dist/lib/validation.js
CHANGED
|
@@ -113,6 +113,8 @@ export const UpdateDescriptionSchema = z.object({
|
|
|
113
113
|
});
|
|
114
114
|
export const RunJqlSchema = z.object({
|
|
115
115
|
limit: NumericStringSchema.optional(),
|
|
116
|
+
query: z.string().optional(),
|
|
117
|
+
listQueries: z.boolean().optional(),
|
|
116
118
|
});
|
|
117
119
|
export const TimeframeSchema = z.string().regex(/^\d+d$/, 'Timeframe must be in format like "7d" or "30d"');
|
|
118
120
|
export const GetPersonWorklogSchema = z.object({
|
|
@@ -157,10 +159,12 @@ export const OrganizationSettingsSchema = z.object({
|
|
|
157
159
|
'allowed-commands': z.array(z.string()).nullish().transform(val => val || DEFAULT_ALLOWED_COMMANDS),
|
|
158
160
|
'allowed-confluence-spaces': z.array(z.string()).nullish().transform(val => val || ['all']),
|
|
159
161
|
});
|
|
162
|
+
export const SavedQueryNameSchema = z.string().regex(/^[a-z0-9][a-z0-9-]*[a-z0-9]$|^[a-z0-9]$/, 'Query name must be lowercase alphanumeric with hyphens (e.g., "my-query"), cannot start or end with a hyphen');
|
|
160
163
|
export const SettingsSchema = z.object({
|
|
161
164
|
defaults: OrganizationSettingsSchema.optional(),
|
|
162
165
|
projects: z.array(ProjectSettingSchema).optional(),
|
|
163
166
|
commands: z.array(z.string()).optional(),
|
|
167
|
+
savedQueries: z.record(SavedQueryNameSchema, z.string().min(1)).optional(),
|
|
164
168
|
});
|
|
165
169
|
// =============================================================================
|
|
166
170
|
// EPIC VALIDATION SCHEMAS
|
package/package.json
CHANGED
package/settings.yaml
CHANGED
|
@@ -14,3 +14,12 @@ commands:
|
|
|
14
14
|
- run-jql
|
|
15
15
|
- list-issue-types
|
|
16
16
|
- project-statuses
|
|
17
|
+
|
|
18
|
+
# Saved Queries: Define reusable JQL queries by name.
|
|
19
|
+
# Keys must be lowercase alphanumeric with optional hyphens (e.g., "my-query").
|
|
20
|
+
# Values are JQL query strings. Saved queries are used with:
|
|
21
|
+
# jira-ai issue search --query <name>
|
|
22
|
+
# jira-ai issue search --list-queries
|
|
23
|
+
# saved-queries:
|
|
24
|
+
# my-open-bugs: "project = PROJ AND status = Open AND issuetype = Bug"
|
|
25
|
+
# overdue-tasks: "project = PROJ AND duedate < now() AND status != Done"
|