jira-ai 0.3.18 → 0.3.19
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/dist/cli.js +4 -1
- package/dist/commands/task-with-details.js +6 -2
- package/dist/lib/formatters.js +27 -0
- package/dist/lib/jira-client.js +31 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -32,7 +32,7 @@ const program = new Command();
|
|
|
32
32
|
program
|
|
33
33
|
.name('jira-ai')
|
|
34
34
|
.description('CLI tool for interacting with Atlassian Jira')
|
|
35
|
-
.version('0.3.
|
|
35
|
+
.version('0.3.19')
|
|
36
36
|
.option('-o, --organization <alias>', 'Override the active Jira organization');
|
|
37
37
|
// Hook to handle the global option before any command runs
|
|
38
38
|
program.on('option:organization', (alias) => {
|
|
@@ -113,6 +113,9 @@ program
|
|
|
113
113
|
program
|
|
114
114
|
.command('task-with-details <task-id>')
|
|
115
115
|
.description('Show task title, body, and comments')
|
|
116
|
+
.option('--include-detailed-history', 'Include the full history of task actions')
|
|
117
|
+
.option('--history-limit <number>', 'Number of history entries to show (default: 50)', '50')
|
|
118
|
+
.option('--history-offset <number>', 'Number of history entries to skip (default: 0)', '0')
|
|
116
119
|
.action(withPermission('task-with-details', taskWithDetailsCommand, {
|
|
117
120
|
validateArgs: (args) => validateOptions(IssueKeySchema, args[0])
|
|
118
121
|
}));
|
|
@@ -3,10 +3,14 @@ import { getTaskWithDetails } from '../lib/jira-client.js';
|
|
|
3
3
|
import { formatTaskDetails } from '../lib/formatters.js';
|
|
4
4
|
import { CommandError } from '../lib/errors.js';
|
|
5
5
|
import { ui } from '../lib/ui.js';
|
|
6
|
-
export async function taskWithDetailsCommand(taskId) {
|
|
6
|
+
export async function taskWithDetailsCommand(taskId, options = {}) {
|
|
7
7
|
ui.startSpinner(`Fetching details for ${taskId}...`);
|
|
8
8
|
try {
|
|
9
|
-
const task = await getTaskWithDetails(taskId
|
|
9
|
+
const task = await getTaskWithDetails(taskId, {
|
|
10
|
+
includeHistory: options.includeDetailedHistory,
|
|
11
|
+
historyLimit: options.historyLimit ? parseInt(options.historyLimit, 10) : undefined,
|
|
12
|
+
historyOffset: options.historyOffset ? parseInt(options.historyOffset, 10) : undefined,
|
|
13
|
+
});
|
|
10
14
|
ui.succeedSpinner(chalk.green('Task details retrieved'));
|
|
11
15
|
console.log(formatTaskDetails(task));
|
|
12
16
|
}
|
package/dist/lib/formatters.js
CHANGED
|
@@ -122,6 +122,33 @@ export function formatTaskDetails(task) {
|
|
|
122
122
|
else {
|
|
123
123
|
output += chalk.gray('No comments yet.\n\n');
|
|
124
124
|
}
|
|
125
|
+
// History
|
|
126
|
+
if (task.history && task.history.length > 0) {
|
|
127
|
+
output += formatTaskHistory(task.history);
|
|
128
|
+
}
|
|
129
|
+
return output;
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Format task history
|
|
133
|
+
*/
|
|
134
|
+
export function formatTaskHistory(history) {
|
|
135
|
+
if (history.length === 0) {
|
|
136
|
+
return chalk.gray('No history entries found.\n\n');
|
|
137
|
+
}
|
|
138
|
+
const table = createTable(['Date', 'Author', 'Field', 'From', 'To'], [22, 18, 15, 25, 25]);
|
|
139
|
+
history.forEach((entry) => {
|
|
140
|
+
entry.items.forEach((item, index) => {
|
|
141
|
+
table.push([
|
|
142
|
+
index === 0 ? formatTimestamp(entry.created) : '',
|
|
143
|
+
index === 0 ? truncate(entry.author, 18) : '',
|
|
144
|
+
chalk.yellow(item.field),
|
|
145
|
+
truncate(item.from || chalk.gray('None'), 25),
|
|
146
|
+
truncate(item.to || chalk.gray('None'), 25),
|
|
147
|
+
]);
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
let output = '\n' + chalk.bold(`Task History (${history.length} entries)`) + '\n';
|
|
151
|
+
output += table.toString() + '\n';
|
|
125
152
|
return output;
|
|
126
153
|
}
|
|
127
154
|
/**
|
package/dist/lib/jira-client.js
CHANGED
|
@@ -105,11 +105,13 @@ export async function getProjects() {
|
|
|
105
105
|
/**
|
|
106
106
|
* Get task details with comments
|
|
107
107
|
*/
|
|
108
|
-
export async function getTaskWithDetails(taskId) {
|
|
108
|
+
export async function getTaskWithDetails(taskId, options = {}) {
|
|
109
109
|
const client = getJiraClient();
|
|
110
|
+
const { includeHistory, historyLimit = 50, historyOffset = 0 } = options;
|
|
110
111
|
// Get issue details
|
|
111
112
|
const issue = await client.issues.getIssue({
|
|
112
113
|
issueIdOrKey: taskId,
|
|
114
|
+
expand: includeHistory ? 'changelog' : undefined,
|
|
113
115
|
fields: [
|
|
114
116
|
'summary',
|
|
115
117
|
'description',
|
|
@@ -157,6 +159,33 @@ export async function getTaskWithDetails(taskId) {
|
|
|
157
159
|
name: subtask.fields?.status?.name || 'Unknown',
|
|
158
160
|
},
|
|
159
161
|
})) || [];
|
|
162
|
+
// Extract history if requested
|
|
163
|
+
let history = undefined;
|
|
164
|
+
if (includeHistory && issue.changelog) {
|
|
165
|
+
let allHistories = issue.changelog.histories || [];
|
|
166
|
+
// If there are more histories than returned in the initial expand, we might need to fetch more
|
|
167
|
+
// Jira usually returns 100 histories in the expand.
|
|
168
|
+
if (issue.changelog.total && issue.changelog.total > allHistories.length && (historyOffset + historyLimit) > allHistories.length) {
|
|
169
|
+
const moreHistories = await client.issues.getChangeLogs({
|
|
170
|
+
issueIdOrKey: taskId,
|
|
171
|
+
});
|
|
172
|
+
allHistories = moreHistories.values || allHistories;
|
|
173
|
+
}
|
|
174
|
+
history = allHistories.map((h) => ({
|
|
175
|
+
id: h.id,
|
|
176
|
+
author: h.author?.displayName || 'Unknown',
|
|
177
|
+
created: h.created,
|
|
178
|
+
items: h.items?.map((item) => ({
|
|
179
|
+
field: item.field || '',
|
|
180
|
+
from: item.fromString,
|
|
181
|
+
to: item.toString
|
|
182
|
+
}))
|
|
183
|
+
}));
|
|
184
|
+
// Sort by date descending (most recent first)
|
|
185
|
+
history.sort((a, b) => new Date(b.created).getTime() - new Date(a.created).getTime());
|
|
186
|
+
// Apply offset and limit
|
|
187
|
+
history = history.slice(historyOffset, historyOffset + historyLimit);
|
|
188
|
+
}
|
|
160
189
|
return {
|
|
161
190
|
id: issue.id || '',
|
|
162
191
|
key: issue.key || '',
|
|
@@ -179,6 +208,7 @@ export async function getTaskWithDetails(taskId) {
|
|
|
179
208
|
comments,
|
|
180
209
|
parent,
|
|
181
210
|
subtasks,
|
|
211
|
+
history,
|
|
182
212
|
};
|
|
183
213
|
}
|
|
184
214
|
/**
|