baton-issue-tracker 1.8.0 → 1.9.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baton-issue-tracker",
3
- "version": "1.8.0",
3
+ "version": "1.9.0",
4
4
  "description": "A CLI issue tracker for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
package/source/cli.js CHANGED
@@ -18,6 +18,7 @@ import { run as runNext } from './commands/next.js';
18
18
  import { run as runLoop } from './commands/loop.js';
19
19
  import { run as runStatus } from './commands/status.js';
20
20
  import { run as runApprove } from './commands/approve.js';
21
+ import { run as runReject } from './commands/reject.js';
21
22
  import { wantsHelp } from './util.js';
22
23
  import { run as runView} from './commands/view.js';
23
24
  import { run as runSearch } from './commands/search.js';
@@ -78,6 +79,7 @@ Options:
78
79
  create --token-limit <n> Optional token budget for this issue
79
80
  create --json Output as JSON (for AI agents)
80
81
  approve <id> [--json]
82
+ reject <id> --reason <text> Reject an issue with a given reason
81
83
  priority <id> <level> [--json] low | medium | high
82
84
  update --title <text> New title
83
85
  update --description <text> New description
@@ -138,6 +140,7 @@ async function main() {
138
140
  search: () => runSearch(args),
139
141
  list: () => runList(args),
140
142
  approve: () => runApprove(args),
143
+ reject: () => runReject(args),
141
144
  priority: () => runPriority(args),
142
145
  create: () => runCreate(args),
143
146
  update: () => runUpdate(args),
@@ -0,0 +1,99 @@
1
+ // reject.js
2
+ // supports rejecting an issue.
3
+ //
4
+ // AI Was used in generating this file.
5
+ // Usage:
6
+ // baton reject <id> [options]
7
+ //
8
+ // Options:
9
+ // --reason <text> Reason for rejection (required)
10
+ // --json Output in JSON format
11
+ // -h, --help Show this help
12
+ //
13
+ // Examples:
14
+ // baton reject 5 --reason "Needs more detail"
15
+
16
+ import { rejectIssue, getIssue } from '../services/issuesService.js';
17
+ import { Status } from '../models/issue.js';
18
+ import { hasFlag, getFlagValue, wantsHelp, renderOutput, renderError, serializeIssue } from '../util.js';
19
+
20
+ const USAGE = "Usage:\n baton reject <id> [options]\n\nOptions:\n --reason <text> Reason for rejection (required)\n --json Output in JSON format\n -h, --help Show this help";
21
+
22
+ /**
23
+ * Rejects an issue for a specified ID.
24
+ *
25
+ * @param {string[]} args - The command line arguments
26
+ * @returns {Promise<number>} The exit code: 0 is success, 1 is error.
27
+ */
28
+ export async function run(args) {
29
+ const isJson = hasFlag(args, '--json');
30
+
31
+ // (0) Help check
32
+ if (wantsHelp(args)) {
33
+ console.log(USAGE);
34
+ return 0;
35
+ }
36
+
37
+ // (1) Parse arguments
38
+ const idArgs = args.filter(arg => !arg.startsWith('-'));
39
+ if (idArgs.length === 0) {
40
+ renderError(isJson, `No ID provided.\n${USAGE}`, 'MISSING_ID');
41
+ return 1;
42
+ }
43
+
44
+ const id = Number(idArgs[0]);
45
+ if (!Number.isInteger(id)) {
46
+ renderError(isJson, `Invalid ID "${idArgs[0]}". ID must be an integer.`, 'INVALID_ID');
47
+ return 1;
48
+ }
49
+
50
+ if (!hasFlag(args, "--reason")) {
51
+ renderError(isJson, `Missing reason for reject.\n${USAGE}`, 'MISSING_REASON');
52
+ return 1;
53
+ }
54
+
55
+ let reasonText;
56
+ try {
57
+ reasonText = getFlagValue(args, "--reason");
58
+ } catch (error) {
59
+ renderError(isJson, error.message, 'INVALID_REASON');
60
+ return 1;
61
+ }
62
+
63
+ if (!reasonText || reasonText.trim() === "") {
64
+ renderError(isJson, "Reason for rejection cannot be empty.", 'EMPTY_REASON');
65
+ return 1;
66
+ }
67
+
68
+ let issue;
69
+ try {
70
+ issue = await getIssue(id);
71
+ } catch (error) {
72
+ if (error.message.includes("not found")) {
73
+ renderError(isJson, error.message, 'NOT_FOUND');
74
+ } else {
75
+ renderError(isJson, error.message);
76
+ }
77
+ return 1;
78
+ }
79
+
80
+ if (issue.status !== Status.IN_REVIEW) {
81
+ renderError(isJson, `Issue #${id} is currently "${issue.status}". Only issues in "${Status.IN_REVIEW}" status can be rejected.`, 'INVALID_STATE');
82
+ return 1;
83
+ }
84
+
85
+ try {
86
+ // (3) Perform rejection
87
+ const updatedIssue = await rejectIssue(id, reasonText);
88
+ const envelope = { status: 'success', issue: serializeIssue(updatedIssue) };
89
+
90
+ renderOutput(isJson, envelope, () => {
91
+ console.log(`Issue #${id} rejected successfully and moved back to "${updatedIssue.status}".`);
92
+ });
93
+
94
+ return 0;
95
+ } catch (error) {
96
+ renderError(isJson, error.message);
97
+ return 1;
98
+ }
99
+ }