baton-issue-tracker 1.3.1
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 +13 -0
- package/drizzle/0000_tidy_enchantress.sql +18 -0
- package/drizzle/0001_salty_luke_cage.sql +16 -0
- package/drizzle/meta/0000_snapshot.json +135 -0
- package/drizzle/meta/0001_snapshot.json +156 -0
- package/drizzle/meta/_journal.json +20 -0
- package/package.json +43 -0
- package/source/cli.js +133 -0
- package/source/commands/approve.js +43 -0
- package/source/commands/create.js +48 -0
- package/source/commands/init.js +171 -0
- package/source/commands/list.js +67 -0
- package/source/commands/loop.js +63 -0
- package/source/commands/next.js +46 -0
- package/source/commands/search.js +44 -0
- package/source/commands/status.js +55 -0
- package/source/commands/update.js +74 -0
- package/source/commands/view.js +46 -0
- package/source/db/index.js +72 -0
- package/source/index.js +1 -0
- package/source/models/activityLog.js +23 -0
- package/source/models/issue.js +72 -0
- package/source/models/schema.js +53 -0
- package/source/services/issuesService.js +476 -0
- package/source/temp.md +1 -0
- package/source/util.js +260 -0
package/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
CREATE TABLE `activity` (
|
|
2
|
+
`log_id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
3
|
+
`issue_id` integer,
|
|
4
|
+
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
5
|
+
`action` text NOT NULL,
|
|
6
|
+
`details` text
|
|
7
|
+
);
|
|
8
|
+
--> statement-breakpoint
|
|
9
|
+
CREATE TABLE `issues` (
|
|
10
|
+
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
11
|
+
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
12
|
+
`attempt_num` integer DEFAULT 0 NOT NULL,
|
|
13
|
+
`title` text DEFAULT 'PENDING' NOT NULL,
|
|
14
|
+
`status` text DEFAULT 'Open' NOT NULL,
|
|
15
|
+
`priority` text DEFAULT 'Low',
|
|
16
|
+
`token_limit` integer,
|
|
17
|
+
`description` text
|
|
18
|
+
);
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
ALTER TABLE `issues` ADD `last_updated` text DEFAULT CURRENT_TIMESTAMP NOT NULL;--> statement-breakpoint
|
|
2
|
+
ALTER TABLE `issues` ADD `assignees` text DEFAULT '[]';--> statement-breakpoint
|
|
3
|
+
PRAGMA foreign_keys=OFF;--> statement-breakpoint
|
|
4
|
+
CREATE TABLE `__new_activity` (
|
|
5
|
+
`log_id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
|
|
6
|
+
`issue_id` integer,
|
|
7
|
+
`created_at` text DEFAULT CURRENT_TIMESTAMP NOT NULL,
|
|
8
|
+
`action` text NOT NULL,
|
|
9
|
+
`details` text,
|
|
10
|
+
CONSTRAINT "activity_action_check" CHECK("__new_activity"."action" IN ('state_change', 'priority_change', 'edit', 'read', 'creation', 'deletion', 'rejection'))
|
|
11
|
+
);
|
|
12
|
+
--> statement-breakpoint
|
|
13
|
+
INSERT INTO `__new_activity`("log_id", "issue_id", "created_at", "action", "details") SELECT "log_id", "issue_id", "created_at", "action", "details" FROM `activity`;--> statement-breakpoint
|
|
14
|
+
DROP TABLE `activity`;--> statement-breakpoint
|
|
15
|
+
ALTER TABLE `__new_activity` RENAME TO `activity`;--> statement-breakpoint
|
|
16
|
+
PRAGMA foreign_keys=ON;
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "6",
|
|
3
|
+
"dialect": "sqlite",
|
|
4
|
+
"id": "3a9e6e25-7620-4cef-9154-95ab093513fc",
|
|
5
|
+
"prevId": "00000000-0000-0000-0000-000000000000",
|
|
6
|
+
"tables": {
|
|
7
|
+
"activity": {
|
|
8
|
+
"name": "activity",
|
|
9
|
+
"columns": {
|
|
10
|
+
"log_id": {
|
|
11
|
+
"name": "log_id",
|
|
12
|
+
"type": "integer",
|
|
13
|
+
"primaryKey": true,
|
|
14
|
+
"notNull": true,
|
|
15
|
+
"autoincrement": true
|
|
16
|
+
},
|
|
17
|
+
"issue_id": {
|
|
18
|
+
"name": "issue_id",
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"primaryKey": false,
|
|
21
|
+
"notNull": false,
|
|
22
|
+
"autoincrement": false
|
|
23
|
+
},
|
|
24
|
+
"created_at": {
|
|
25
|
+
"name": "created_at",
|
|
26
|
+
"type": "text",
|
|
27
|
+
"primaryKey": false,
|
|
28
|
+
"notNull": true,
|
|
29
|
+
"autoincrement": false,
|
|
30
|
+
"default": "CURRENT_TIMESTAMP"
|
|
31
|
+
},
|
|
32
|
+
"action": {
|
|
33
|
+
"name": "action",
|
|
34
|
+
"type": "text",
|
|
35
|
+
"primaryKey": false,
|
|
36
|
+
"notNull": true,
|
|
37
|
+
"autoincrement": false
|
|
38
|
+
},
|
|
39
|
+
"details": {
|
|
40
|
+
"name": "details",
|
|
41
|
+
"type": "text",
|
|
42
|
+
"primaryKey": false,
|
|
43
|
+
"notNull": false,
|
|
44
|
+
"autoincrement": false
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"indexes": {},
|
|
48
|
+
"foreignKeys": {},
|
|
49
|
+
"compositePrimaryKeys": {},
|
|
50
|
+
"uniqueConstraints": {},
|
|
51
|
+
"checkConstraints": {}
|
|
52
|
+
},
|
|
53
|
+
"issues": {
|
|
54
|
+
"name": "issues",
|
|
55
|
+
"columns": {
|
|
56
|
+
"id": {
|
|
57
|
+
"name": "id",
|
|
58
|
+
"type": "integer",
|
|
59
|
+
"primaryKey": true,
|
|
60
|
+
"notNull": true,
|
|
61
|
+
"autoincrement": true
|
|
62
|
+
},
|
|
63
|
+
"created_at": {
|
|
64
|
+
"name": "created_at",
|
|
65
|
+
"type": "text",
|
|
66
|
+
"primaryKey": false,
|
|
67
|
+
"notNull": true,
|
|
68
|
+
"autoincrement": false,
|
|
69
|
+
"default": "CURRENT_TIMESTAMP"
|
|
70
|
+
},
|
|
71
|
+
"attempt_num": {
|
|
72
|
+
"name": "attempt_num",
|
|
73
|
+
"type": "integer",
|
|
74
|
+
"primaryKey": false,
|
|
75
|
+
"notNull": true,
|
|
76
|
+
"autoincrement": false,
|
|
77
|
+
"default": 0
|
|
78
|
+
},
|
|
79
|
+
"title": {
|
|
80
|
+
"name": "title",
|
|
81
|
+
"type": "text",
|
|
82
|
+
"primaryKey": false,
|
|
83
|
+
"notNull": true,
|
|
84
|
+
"autoincrement": false,
|
|
85
|
+
"default": "'PENDING'"
|
|
86
|
+
},
|
|
87
|
+
"status": {
|
|
88
|
+
"name": "status",
|
|
89
|
+
"type": "text",
|
|
90
|
+
"primaryKey": false,
|
|
91
|
+
"notNull": true,
|
|
92
|
+
"autoincrement": false,
|
|
93
|
+
"default": "'Open'"
|
|
94
|
+
},
|
|
95
|
+
"priority": {
|
|
96
|
+
"name": "priority",
|
|
97
|
+
"type": "text",
|
|
98
|
+
"primaryKey": false,
|
|
99
|
+
"notNull": false,
|
|
100
|
+
"autoincrement": false,
|
|
101
|
+
"default": "'Low'"
|
|
102
|
+
},
|
|
103
|
+
"token_limit": {
|
|
104
|
+
"name": "token_limit",
|
|
105
|
+
"type": "integer",
|
|
106
|
+
"primaryKey": false,
|
|
107
|
+
"notNull": false,
|
|
108
|
+
"autoincrement": false
|
|
109
|
+
},
|
|
110
|
+
"description": {
|
|
111
|
+
"name": "description",
|
|
112
|
+
"type": "text",
|
|
113
|
+
"primaryKey": false,
|
|
114
|
+
"notNull": false,
|
|
115
|
+
"autoincrement": false
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
"indexes": {},
|
|
119
|
+
"foreignKeys": {},
|
|
120
|
+
"compositePrimaryKeys": {},
|
|
121
|
+
"uniqueConstraints": {},
|
|
122
|
+
"checkConstraints": {}
|
|
123
|
+
}
|
|
124
|
+
},
|
|
125
|
+
"views": {},
|
|
126
|
+
"enums": {},
|
|
127
|
+
"_meta": {
|
|
128
|
+
"schemas": {},
|
|
129
|
+
"tables": {},
|
|
130
|
+
"columns": {}
|
|
131
|
+
},
|
|
132
|
+
"internal": {
|
|
133
|
+
"indexes": {}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "6",
|
|
3
|
+
"dialect": "sqlite",
|
|
4
|
+
"id": "af5467aa-0757-4c91-8afb-c6f0202dd90c",
|
|
5
|
+
"prevId": "3a9e6e25-7620-4cef-9154-95ab093513fc",
|
|
6
|
+
"tables": {
|
|
7
|
+
"activity": {
|
|
8
|
+
"name": "activity",
|
|
9
|
+
"columns": {
|
|
10
|
+
"log_id": {
|
|
11
|
+
"name": "log_id",
|
|
12
|
+
"type": "integer",
|
|
13
|
+
"primaryKey": true,
|
|
14
|
+
"notNull": true,
|
|
15
|
+
"autoincrement": true
|
|
16
|
+
},
|
|
17
|
+
"issue_id": {
|
|
18
|
+
"name": "issue_id",
|
|
19
|
+
"type": "integer",
|
|
20
|
+
"primaryKey": false,
|
|
21
|
+
"notNull": false,
|
|
22
|
+
"autoincrement": false
|
|
23
|
+
},
|
|
24
|
+
"created_at": {
|
|
25
|
+
"name": "created_at",
|
|
26
|
+
"type": "text",
|
|
27
|
+
"primaryKey": false,
|
|
28
|
+
"notNull": true,
|
|
29
|
+
"autoincrement": false,
|
|
30
|
+
"default": "CURRENT_TIMESTAMP"
|
|
31
|
+
},
|
|
32
|
+
"action": {
|
|
33
|
+
"name": "action",
|
|
34
|
+
"type": "text",
|
|
35
|
+
"primaryKey": false,
|
|
36
|
+
"notNull": true,
|
|
37
|
+
"autoincrement": false
|
|
38
|
+
},
|
|
39
|
+
"details": {
|
|
40
|
+
"name": "details",
|
|
41
|
+
"type": "text",
|
|
42
|
+
"primaryKey": false,
|
|
43
|
+
"notNull": false,
|
|
44
|
+
"autoincrement": false
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"indexes": {},
|
|
48
|
+
"foreignKeys": {},
|
|
49
|
+
"compositePrimaryKeys": {},
|
|
50
|
+
"uniqueConstraints": {},
|
|
51
|
+
"checkConstraints": {
|
|
52
|
+
"activity_action_check": {
|
|
53
|
+
"name": "activity_action_check",
|
|
54
|
+
"value": "\"activity\".\"action\" IN ('state_change', 'priority_change', 'edit', 'read', 'creation', 'deletion', 'rejection')"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
"issues": {
|
|
59
|
+
"name": "issues",
|
|
60
|
+
"columns": {
|
|
61
|
+
"id": {
|
|
62
|
+
"name": "id",
|
|
63
|
+
"type": "integer",
|
|
64
|
+
"primaryKey": true,
|
|
65
|
+
"notNull": true,
|
|
66
|
+
"autoincrement": true
|
|
67
|
+
},
|
|
68
|
+
"created_at": {
|
|
69
|
+
"name": "created_at",
|
|
70
|
+
"type": "text",
|
|
71
|
+
"primaryKey": false,
|
|
72
|
+
"notNull": true,
|
|
73
|
+
"autoincrement": false,
|
|
74
|
+
"default": "CURRENT_TIMESTAMP"
|
|
75
|
+
},
|
|
76
|
+
"last_updated": {
|
|
77
|
+
"name": "last_updated",
|
|
78
|
+
"type": "text",
|
|
79
|
+
"primaryKey": false,
|
|
80
|
+
"notNull": true,
|
|
81
|
+
"autoincrement": false,
|
|
82
|
+
"default": "CURRENT_TIMESTAMP"
|
|
83
|
+
},
|
|
84
|
+
"attempt_num": {
|
|
85
|
+
"name": "attempt_num",
|
|
86
|
+
"type": "integer",
|
|
87
|
+
"primaryKey": false,
|
|
88
|
+
"notNull": true,
|
|
89
|
+
"autoincrement": false,
|
|
90
|
+
"default": 0
|
|
91
|
+
},
|
|
92
|
+
"title": {
|
|
93
|
+
"name": "title",
|
|
94
|
+
"type": "text",
|
|
95
|
+
"primaryKey": false,
|
|
96
|
+
"notNull": true,
|
|
97
|
+
"autoincrement": false,
|
|
98
|
+
"default": "'PENDING'"
|
|
99
|
+
},
|
|
100
|
+
"status": {
|
|
101
|
+
"name": "status",
|
|
102
|
+
"type": "text",
|
|
103
|
+
"primaryKey": false,
|
|
104
|
+
"notNull": true,
|
|
105
|
+
"autoincrement": false,
|
|
106
|
+
"default": "'Open'"
|
|
107
|
+
},
|
|
108
|
+
"priority": {
|
|
109
|
+
"name": "priority",
|
|
110
|
+
"type": "text",
|
|
111
|
+
"primaryKey": false,
|
|
112
|
+
"notNull": false,
|
|
113
|
+
"autoincrement": false,
|
|
114
|
+
"default": "'Low'"
|
|
115
|
+
},
|
|
116
|
+
"token_limit": {
|
|
117
|
+
"name": "token_limit",
|
|
118
|
+
"type": "integer",
|
|
119
|
+
"primaryKey": false,
|
|
120
|
+
"notNull": false,
|
|
121
|
+
"autoincrement": false
|
|
122
|
+
},
|
|
123
|
+
"description": {
|
|
124
|
+
"name": "description",
|
|
125
|
+
"type": "text",
|
|
126
|
+
"primaryKey": false,
|
|
127
|
+
"notNull": false,
|
|
128
|
+
"autoincrement": false
|
|
129
|
+
},
|
|
130
|
+
"assignees": {
|
|
131
|
+
"name": "assignees",
|
|
132
|
+
"type": "text",
|
|
133
|
+
"primaryKey": false,
|
|
134
|
+
"notNull": false,
|
|
135
|
+
"autoincrement": false,
|
|
136
|
+
"default": "'[]'"
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
"indexes": {},
|
|
140
|
+
"foreignKeys": {},
|
|
141
|
+
"compositePrimaryKeys": {},
|
|
142
|
+
"uniqueConstraints": {},
|
|
143
|
+
"checkConstraints": {}
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
"views": {},
|
|
147
|
+
"enums": {},
|
|
148
|
+
"_meta": {
|
|
149
|
+
"schemas": {},
|
|
150
|
+
"tables": {},
|
|
151
|
+
"columns": {}
|
|
152
|
+
},
|
|
153
|
+
"internal": {
|
|
154
|
+
"indexes": {}
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "7",
|
|
3
|
+
"dialect": "sqlite",
|
|
4
|
+
"entries": [
|
|
5
|
+
{
|
|
6
|
+
"idx": 0,
|
|
7
|
+
"version": "6",
|
|
8
|
+
"when": 1779934723405,
|
|
9
|
+
"tag": "0000_tidy_enchantress",
|
|
10
|
+
"breakpoints": true
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"idx": 1,
|
|
14
|
+
"version": "6",
|
|
15
|
+
"when": 1780114722528,
|
|
16
|
+
"tag": "0001_salty_luke_cage",
|
|
17
|
+
"breakpoints": true
|
|
18
|
+
}
|
|
19
|
+
]
|
|
20
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "baton-issue-tracker",
|
|
3
|
+
"version": "1.3.1",
|
|
4
|
+
"description": "A CLI issue tracker for AI agents",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"baton": "source/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"source/",
|
|
11
|
+
"drizzle/"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"test": "node --test",
|
|
15
|
+
"lint": "eslint source/",
|
|
16
|
+
"lint:fix": "eslint source/ --fix",
|
|
17
|
+
"prepare": "husky",
|
|
18
|
+
"commitlint": "commitlint --edit",
|
|
19
|
+
"semantic-release": "semantic-release",
|
|
20
|
+
"build-docs": "jsdoc --pedantic -r source -d docs/jsdoc"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@commitlint/cli": "^21.0.1",
|
|
24
|
+
"@commitlint/config-conventional": "^21.0.1",
|
|
25
|
+
"@eslint/js": "^9.0.0",
|
|
26
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
27
|
+
"@semantic-release/git": "^10.0.1",
|
|
28
|
+
"@semantic-release/npm": "^13.1.5",
|
|
29
|
+
"drizzle-kit": "^0.31.10",
|
|
30
|
+
"eslint": "^9.0.0",
|
|
31
|
+
"globals": "^17.6.0",
|
|
32
|
+
"husky": "^9.1.7",
|
|
33
|
+
"jsdoc": "^4.0.5",
|
|
34
|
+
"semantic-release": "^25.0.3"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"node": ">=22.0.0"
|
|
38
|
+
},
|
|
39
|
+
"dependencies": {
|
|
40
|
+
"better-sqlite3": "^12.10.0",
|
|
41
|
+
"drizzle-orm": "^0.45.2"
|
|
42
|
+
}
|
|
43
|
+
}
|
package/source/cli.js
ADDED
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
// cli.js
|
|
3
|
+
// AI was consulted for large portions of this file.
|
|
4
|
+
// CLI for the issue tracker which allows the user to interact with the tracker.
|
|
5
|
+
// usage: baton [command] [options]
|
|
6
|
+
// commands:
|
|
7
|
+
// init: initialize the tracker
|
|
8
|
+
// next: work on the next issue
|
|
9
|
+
// loop: run the agent autonomously for multiple steps
|
|
10
|
+
// status: show issue counts and overall progress
|
|
11
|
+
//
|
|
12
|
+
// see each command's file for more detailed flags specifications.
|
|
13
|
+
/**
|
|
14
|
+
* Imports the run functions from each command.
|
|
15
|
+
*/
|
|
16
|
+
import { run as runInit } from './commands/init.js';
|
|
17
|
+
import { run as runNext } from './commands/next.js';
|
|
18
|
+
import { run as runLoop } from './commands/loop.js';
|
|
19
|
+
import { run as runStatus } from './commands/status.js';
|
|
20
|
+
import { run as runApprove } from './commands/approve.js';
|
|
21
|
+
import { wantsHelp } from './util.js';
|
|
22
|
+
import { run as runView} from './commands/view.js';
|
|
23
|
+
import { run as runSearch } from './commands/search.js';
|
|
24
|
+
import { run as runList } from './commands/list.js';
|
|
25
|
+
import { run as runCreate } from './commands/create.js'
|
|
26
|
+
import { run as runUpdate } from './commands/update.js'
|
|
27
|
+
|
|
28
|
+
const HELP = `baton — AI agent issue tracker CLI
|
|
29
|
+
|
|
30
|
+
Usage:
|
|
31
|
+
baton <command> [options]
|
|
32
|
+
|
|
33
|
+
Commands:
|
|
34
|
+
init Initialize storage and seed issues from product specs
|
|
35
|
+
next Work on the highest-priority open issue
|
|
36
|
+
loop Run the agent autonomously for multiple steps
|
|
37
|
+
status Show issue counts and overall progress
|
|
38
|
+
view View all issue fields for a given issue ID
|
|
39
|
+
search Search issues by title and description (case insensitive)
|
|
40
|
+
list Lists issues filtered by status and priority
|
|
41
|
+
create Creates an issue with specified fields
|
|
42
|
+
approve Move an issue from in-review to closed
|
|
43
|
+
update Updates an issue's specified fields
|
|
44
|
+
|
|
45
|
+
Options:
|
|
46
|
+
init --force Re-initialize an existing tracker database
|
|
47
|
+
init --specs <path> Path to product specs file (overrides default)
|
|
48
|
+
init <path> Same as --specs <path> (positional)
|
|
49
|
+
Default specs: docs/specs/project-requirements.md
|
|
50
|
+
loop --steps <n> Number of autonomous steps (alias: -n)
|
|
51
|
+
loop -n <n>
|
|
52
|
+
view <id>
|
|
53
|
+
search <query>
|
|
54
|
+
list --status <s> Filter by status: open | in-progress | closed
|
|
55
|
+
list --priority <p> Filter by priority: low | medium | high
|
|
56
|
+
list --limit <n> Max results (default: 50)
|
|
57
|
+
list --offset <n> Skip first n results (default: 0)
|
|
58
|
+
create --title <text> Issue title (defaults to "Issue #<id>" if omitted)
|
|
59
|
+
create --description <text> Issue description
|
|
60
|
+
create --priority <level> low | medium | high (default: low)
|
|
61
|
+
create --token-limit <n> Optional token budget for this issue
|
|
62
|
+
approve <id>
|
|
63
|
+
update --title <text> New title
|
|
64
|
+
update --description <text> New description
|
|
65
|
+
update --token-limit <n> New token budget
|
|
66
|
+
update --status <s> open | in-progress | closed
|
|
67
|
+
update --priority <level> low | medium | high
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
baton init
|
|
72
|
+
baton init --specs ./my-specs.md
|
|
73
|
+
baton init ./my-specs.md
|
|
74
|
+
baton init --force
|
|
75
|
+
baton next
|
|
76
|
+
baton loop --steps 5
|
|
77
|
+
baton status
|
|
78
|
+
baton view 29
|
|
79
|
+
baton search system
|
|
80
|
+
baton list
|
|
81
|
+
baton list --status open --priority high
|
|
82
|
+
baton list --limit 10 --offset 20
|
|
83
|
+
baton create --title "Fix login bug" --priority high
|
|
84
|
+
baton create --title "Refactor auth" --description "Clean up JWT logic" --token-limit 4000
|
|
85
|
+
baton approve 5
|
|
86
|
+
baton update 3 --title "Revised title"
|
|
87
|
+
baton update 7 --status closed --priority medium
|
|
88
|
+
`;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Main function that runs the CLI.
|
|
92
|
+
* @returns {Promise<void>} The exit code: 0 is success, 1 is error, 2 is invalid input.
|
|
93
|
+
*/
|
|
94
|
+
async function main() {
|
|
95
|
+
const [, , command, ...args] = process.argv;
|
|
96
|
+
|
|
97
|
+
if (!command || command === 'help' || wantsHelp(args) || command === '--help') {
|
|
98
|
+
console.log(HELP);
|
|
99
|
+
process.exit(command ? 0 : 1);
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
const handlers = {
|
|
104
|
+
init: () => runInit(args),
|
|
105
|
+
next: () => runNext(args),
|
|
106
|
+
loop: () => runLoop(args),
|
|
107
|
+
status: () => runStatus(args),
|
|
108
|
+
view: () => runView(args),
|
|
109
|
+
search: () => runSearch(args),
|
|
110
|
+
list: () => runList(args),
|
|
111
|
+
approve: () => runApprove(args),
|
|
112
|
+
create: () => runCreate(args),
|
|
113
|
+
update: () => runUpdate(args)
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const handler = handlers[command];
|
|
117
|
+
if (!handler) {
|
|
118
|
+
console.error(`Error: Unknown command "${command}".`);
|
|
119
|
+
console.error('Run `baton --help` for usage.');
|
|
120
|
+
process.exit(1);
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
const exitCode = await handler();
|
|
126
|
+
process.exit(exitCode ?? 0);
|
|
127
|
+
} catch (error) {
|
|
128
|
+
console.error(`Error: ${error.message}`);
|
|
129
|
+
process.exit(2);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
main();
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
// approve.js
|
|
2
|
+
// AI was (regrettably) consulted for some portions of this file.
|
|
3
|
+
// approve command which allows a user to approve an issue currently under review.
|
|
4
|
+
// Usage: baton approve <id>
|
|
5
|
+
|
|
6
|
+
import { approveIssue } from '../services/issuesService.js';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Approves an issue and moves it to the closed state.
|
|
10
|
+
* @param {string[]} args - the command line arguments.
|
|
11
|
+
* @returns {Promise<number>} the exit code: 0 is success, 1 is error
|
|
12
|
+
*/
|
|
13
|
+
export async function run(args) {
|
|
14
|
+
//check if id argument is empty
|
|
15
|
+
if (args.length == 0) {
|
|
16
|
+
throw new Error(
|
|
17
|
+
'Invalid input: Missing issue ID.\nUsage: baton approve <id>'
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
const id = args.join(' ');
|
|
22
|
+
|
|
23
|
+
//check if ID argument isn't a number
|
|
24
|
+
if (isNaN(id)) {
|
|
25
|
+
throw new Error(
|
|
26
|
+
'Invalid input: ID must be a number.\nUsage: baton approve <id>'
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
//try to approve the issue
|
|
31
|
+
try {
|
|
32
|
+
const issue = await approveIssue(id);
|
|
33
|
+
console.log(
|
|
34
|
+
`Issue #${issue.id} approved and moved to ${issue.status}.`
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
return 0;
|
|
38
|
+
} catch (error) {
|
|
39
|
+
console.error('Error: Failed to approve issue.');
|
|
40
|
+
console.error(error.message);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// create.js
|
|
2
|
+
// AI was consulted for some portions of this file.
|
|
3
|
+
// create command allows the user to create an issue
|
|
4
|
+
// Usage: baton create --title <text> --description <text> --priority <level> --token-limit <n>
|
|
5
|
+
//
|
|
6
|
+
// Examples:
|
|
7
|
+
// baton create --title "Fix login bug" --priority high
|
|
8
|
+
// baton create --title "Refactor auth" --description "Clean up JWT logic" --token-limit 4000
|
|
9
|
+
// Options:
|
|
10
|
+
// --title <text> Issue title (defaults to "Issue #<id>" if omitted)
|
|
11
|
+
// --description <text> Issue description
|
|
12
|
+
// --priority <level> low | medium | high (default: low)
|
|
13
|
+
// --token-limit <n> Optional token budget for this issue
|
|
14
|
+
// -h, --help Show this help
|
|
15
|
+
|
|
16
|
+
import { createIssue } from "../services/issuesService.js";
|
|
17
|
+
import { getFlagValue, getNumericFlag } from "../util.js";
|
|
18
|
+
import { parseArgs } from '../util.js';
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Initializes a new issue in the database with the specified fields
|
|
22
|
+
* @param {string[]} args - The command line arguments
|
|
23
|
+
* @returns {Promise<number>} The exit code: 0 is success, 1 is error.
|
|
24
|
+
*/
|
|
25
|
+
export async function run(args) {
|
|
26
|
+
const validFlags = ['--title', '--description', '--priority', '--token-limit'];
|
|
27
|
+
// Check if user misspelled a flag
|
|
28
|
+
for (const arg of args) {
|
|
29
|
+
if (arg.startsWith('--')) {
|
|
30
|
+
if (!validFlags.includes(arg)) {
|
|
31
|
+
throw new Error(`Unknown flag provided: ${arg}. \nFlags: --title <text>, --description <text>, --priority <level>, --token-limit <n>`);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
try {
|
|
37
|
+
const options = parseArgs(args);
|
|
38
|
+
|
|
39
|
+
const issue = await createIssue(options);
|
|
40
|
+
|
|
41
|
+
// program reaches this line if issue was successfully created
|
|
42
|
+
console.log(`Successfully created issue #${issue.id}: "${issue.title}"`);
|
|
43
|
+
return 0;
|
|
44
|
+
} catch (error) {
|
|
45
|
+
console.error(`Failed to create issue: ${error.message}`);
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
}
|