baton-issue-tracker 1.11.0 → 1.11.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 CHANGED
@@ -1,7 +1,8 @@
1
1
  # Fantastic Four
2
2
 
3
- ## Developer Guide
4
- [Contributing guide](CONTRIBUTING.md)
3
+ ## Documentation
4
+ - [User Guide](docs/USER_GUIDE.md) — How to use Baton CLI.
5
+ - [Developer Guide](docs/CONTRIBUTING.md) — Setting up the development environment.
5
6
 
6
7
  ## Project Details:
7
8
  TBD
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "baton-issue-tracker",
3
- "version": "1.11.0",
3
+ "version": "1.11.1",
4
4
  "description": "A CLI issue tracker for AI agents",
5
5
  "type": "module",
6
6
  "bin": {
package/source/cli.js CHANGED
@@ -5,8 +5,6 @@
5
5
  // usage: baton [command] [options]
6
6
  // commands:
7
7
  // init: initialize the tracker
8
- // next: work on the next issue
9
- // loop: run the agent autonomously for multiple steps
10
8
  // status: show issue counts and overall progress
11
9
  //
12
10
  // see each command's file for more detailed flags specifications.
@@ -14,8 +12,6 @@
14
12
  * Imports the run functions from each command.
15
13
  */
16
14
  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
15
  import { run as runStatus } from './commands/status.js';
20
16
  import { run as runApprove } from './commands/approve.js';
21
17
  import { run as runReject } from './commands/reject.js';
@@ -31,6 +27,7 @@ import { run as runLog } from './commands/log.js';
31
27
  import { run as runRegister } from './commands/register.js';
32
28
  import { run as runAgents } from './commands/agents.js';
33
29
  import { run as runSubmit } from './commands/submit.js';
30
+ import { run as runClaim } from './commands/claim.js';
34
31
 
35
32
  import { authenticateContext } from './services/authService.js';
36
33
 
@@ -43,8 +40,6 @@ Commands:
43
40
  init Initialize storage and seed issues from product specs
44
41
  register Register a new AI agent or human user
45
42
  agents List all registered agents and humans
46
- next Work on the highest-priority open issue
47
- loop Run the agent autonomously for multiple steps
48
43
  status Show issue counts and overall progress
49
44
  view View all issue fields for a given issue ID
50
45
  search Search issues by title and description (case insensitive)
@@ -52,6 +47,7 @@ Commands:
52
47
  create Creates an issue with specified fields
53
48
  approve Move an issue from in-review to closed
54
49
  submit Submit finished work for human review
50
+ claim Claim an issue as the authenticated agent
55
51
  priority Set an issue's priority level
56
52
  update Updates an issue's specified fields
57
53
  delete Deletes an issue
@@ -66,10 +62,6 @@ Options:
66
62
  register --name <name> Name of the agent or user
67
63
  register --type <type> agent | human (default: agent)
68
64
  agents [--json]
69
- loop --steps <n> Number of autonomous steps (alias: -n)
70
- loop -n <n>
71
- loop --json Output as JSON (for AI agents)
72
- next --json Output as JSON (for AI agents)
73
65
  status --json Output as JSON (for AI agents)
74
66
  view <id> [--json]
75
67
  search <query> [--json]
@@ -85,6 +77,7 @@ Options:
85
77
  create --json Output as JSON (for AI agents)
86
78
  approve <id> [--json]
87
79
  submit <id> [--json]
80
+ claim <id> [--json]
88
81
  reject <id> --reason <text> Reject an issue with a given reason
89
82
  priority <id> <level> [--json] low | medium | high
90
83
  update --title <text> New title
@@ -103,8 +96,6 @@ Examples:
103
96
  baton init --force
104
97
  baton register --name claude-dev --type agent
105
98
  baton agents
106
- baton next
107
- baton loop --steps 5
108
99
  baton status
109
100
  baton view 29
110
101
  baton search system
@@ -115,6 +106,7 @@ Examples:
115
106
  baton create --title "Refactor auth" --description "Clean up JWT logic" --token-limit 4000
116
107
  baton approve 5
117
108
  baton submit 14
109
+ baton claim 14
118
110
  baton priority 5 high
119
111
  baton priority 3 low
120
112
  baton update 3 --title "Revised title"
@@ -129,7 +121,7 @@ Examples:
129
121
  async function main() {
130
122
  const [, , command, ...args] = process.argv;
131
123
 
132
- if (!command || command === 'help' || wantsHelp(args) || command === '--help') {
124
+ if (!command || command === 'help' || command === '--help') {
133
125
  console.log(HELP);
134
126
  process.exit(command ? 0 : 1);
135
127
  return;
@@ -142,14 +134,13 @@ async function main() {
142
134
  init: () => runInit(args),
143
135
  register: () => runRegister(args),
144
136
  agents: () => runAgents(args),
145
- next: () => runNext(args),
146
- loop: () => runLoop(args),
147
137
  status: () => runStatus(args),
148
138
  view: () => runView(args),
149
139
  search: () => runSearch(args),
150
140
  list: () => runList(args),
151
141
  approve: () => runApprove(args),
152
142
  reject: () => runReject(args),
143
+ claim: () => runClaim(args),
153
144
  priority: () => runPriority(args),
154
145
  create: () => runCreate(args),
155
146
  update: () => runUpdate(args),
@@ -0,0 +1,71 @@
1
+ // claim.js
2
+ // Allows an agent to officially claim an issue to work on.
3
+ // Usage: baton claim <id> [--json]
4
+
5
+ import { isTrackerReady, claimIssue } from '../services/issuesService.js';
6
+ import { getCurrentActor } from '../services/authService.js';
7
+ import {
8
+ hasFlag,
9
+ renderOutput,
10
+ renderError,
11
+ getFirstPositionalArg,
12
+ serializeIssue,
13
+ reportTrackerNotReady,
14
+ } from '../util.js';
15
+
16
+ /**
17
+ * Claims an issue for the authenticated agent.
18
+ * @param {string[]} args - The command line arguments
19
+ * @returns {Promise<number>} The exit code: 0 is success, 1 is error
20
+ */
21
+ export async function run(args) {
22
+ const isJson = hasFlag(args, '--json');
23
+
24
+ if (hasFlag(args, '-h') || hasFlag(args, '--help')) {
25
+ console.log(`Usage: baton claim <id> [--json]\n\nOptions:\n --json Output as JSON (for AI agents)\n -h, --help Show this help\n\nExamples:\n baton claim 14`);
26
+ return 0;
27
+ }
28
+
29
+ const idArg = getFirstPositionalArg(args, { ignoreFlags: ['--json'] });
30
+
31
+ if (!idArg) {
32
+ renderError(isJson, 'Missing issue ID.\nUsage: baton claim <id>', 'MISSING_ID');
33
+ return 1;
34
+ }
35
+
36
+ const id = Number(idArg);
37
+ if (!Number.isInteger(id)) {
38
+ renderError(isJson, `Invalid ID "${idArg}". ID must be an integer.`, 'INVALID_ID');
39
+ return 1;
40
+ }
41
+
42
+ if (!isTrackerReady()) {
43
+ reportTrackerNotReady();
44
+ return 1;
45
+ }
46
+
47
+ const actor = getCurrentActor();
48
+ if (!actor) {
49
+ renderError(isJson, 'No authenticated actor found. Please sign in with a registered agent.', 'UNAUTHORIZED');
50
+ return 1;
51
+ }
52
+
53
+ if (actor.type !== 'agent') {
54
+ renderError(isJson, 'Only an agent may claim an issue.', 'UNAUTHORIZED');
55
+ return 1;
56
+ }
57
+
58
+ try {
59
+ const updatedIssue = claimIssue(id);
60
+ const envelope = { status: 'success', issue: serializeIssue(updatedIssue) };
61
+
62
+ renderOutput(isJson, envelope, () => {
63
+ console.log(`Success: Issue #${updatedIssue.id} claimed by agent "${actor.name}" and moved to ${updatedIssue.status}.`);
64
+ });
65
+
66
+ return 0;
67
+ } catch (error) {
68
+ renderError(isJson, error.message);
69
+ return 1;
70
+ }
71
+ }
@@ -176,7 +176,7 @@ export async function run(args = []) {
176
176
  console.log(` #${issue.id} [${issue.priority}] ${issue.title}`);
177
177
  }
178
178
  }
179
- console.log('Run `baton status` to review progress or `baton next` to start work.');
179
+ console.log('Run `baton status` to review progress.');
180
180
  });
181
181
 
182
182
  return 0;
@@ -2,6 +2,8 @@ import os from 'os';
2
2
  import { getAgentByName } from './agentsService.js';
3
3
  import { setActiveActor } from './issuesService.js';
4
4
 
5
+ let currentActor = null;
6
+
5
7
  /**
6
8
  * Authenticates the current execution context.
7
9
  * Looks for BATON_AGENT in the environment, falling back to the OS username.
@@ -30,6 +32,7 @@ export function authenticateContext(command) {
30
32
  }
31
33
 
32
34
  // Set the global state for the remainder of this command's lifecycle
35
+ currentActor = agent;
33
36
  setActiveActor(agent.id);
34
37
  } catch (error) {
35
38
  // Gracefully handle the scenario where the database hasn't been initialized yet
@@ -41,4 +44,12 @@ export function authenticateContext(command) {
41
44
  // Rethrow if it's a completely different error
42
45
  throw error;
43
46
  }
47
+ }
48
+
49
+ /**
50
+ * Returns the authenticated actor object for this session.
51
+ * @returns {object|null}
52
+ */
53
+ export function getCurrentActor() {
54
+ return currentActor;
44
55
  }
@@ -1,67 +0,0 @@
1
- // loop.js
2
- // AI was consulted for some portions of this file.
3
- // loop command for the tracker which allows the AI agent to work autonomously for multiple steps.
4
- // usage: baton loop [options]
5
- // options:
6
- // --steps <n>: number of steps to run (default: 1)
7
- // -n <n>: alias for --steps <n>
8
- // <n>: same as --steps <n>
9
- // examples usage of steps flag:
10
- // baton loop --steps 5
11
- // baton loop -n 5
12
-
13
- import { isTrackerReady } from '../services/issuesService.js';
14
- import { getNumericFlag, hasFlag, renderOutput, reportTrackerNotReady } from '../util.js';
15
- import { run as runNext } from './next.js';
16
-
17
- /**
18
- * Parses the flags in the command line argument
19
- * @param {string[]} args - The command line arguments
20
- * @returns {{ steps: number }}
21
- */
22
- function parseLoopFlags(args) {
23
- const stepsFlag = getNumericFlag(args, '--steps') ?? getNumericFlag(args, '-n');
24
- return { steps: stepsFlag ?? 1 };
25
- }
26
-
27
- /**
28
- * Runs the loop command
29
- * @param {string[]} args
30
- * @returns {Promise<number>}
31
- */
32
- export async function run(args = []) {
33
- const isJson = hasFlag(args, '--json');
34
- const loopArgs = args.filter((arg) => arg !== '--json');
35
- const { steps } = parseLoopFlags(loopArgs);
36
-
37
- if (!isTrackerReady()) {
38
- reportTrackerNotReady();
39
- return 1;
40
- }
41
-
42
- if (!Number.isInteger(steps) || steps < 1) {
43
- console.error('Error: --steps must be a positive integer.');
44
- console.error('Usage: baton loop --steps <n>');
45
- return 1;
46
- }
47
-
48
- console.log(`Running baton for ${steps} step(s)...\n`);
49
-
50
- let completed = 0;
51
- for (let step = 1; step <= steps; step += 1) {
52
- console.log(`--- Step ${step}/${steps} ---`);
53
- const code = await runNext();
54
- if (code !== 0) {
55
- return code;
56
- }
57
- completed += 1;
58
- if (step < steps) {
59
- console.log('');
60
- }
61
- }
62
-
63
- renderOutput(isJson, { status: 'success', steps, completed }, () => {
64
- console.log(`\nCompleted ${completed} autonomous step(s).`);
65
- });
66
- return 0;
67
- }
@@ -1,53 +0,0 @@
1
- // next.js
2
- // AI was consulted for some portions of this file.
3
- // next command for the issue tracker which allows the user to manually move the AI from issue to issue.
4
- // usage: baton next
5
-
6
- import {
7
- isTrackerReady,
8
- selectNextIssue,
9
- claimIssue,
10
- } from '../services/issuesService.js';
11
- import { formatTimestamp, hasFlag, renderOutput, reportTrackerNotReady, serializeIssue } from '../util.js';
12
-
13
- /**
14
- * Moves the AI agent to work on the next issue.
15
- * Checks if the tracker is ready and if there are any open issues.
16
- * Prompts user to initialize the tracker if it is not ready.
17
- * Stats are updated on the issue through claimIssue function from init.js.
18
- * @returns {Promise<number>} The exit code: 0 is success, 1 is error.
19
- */
20
- export async function run(args = []) {
21
- const isJson = hasFlag(args, '--json');
22
-
23
- if (!isTrackerReady()) {
24
- reportTrackerNotReady();
25
- return 1;
26
- }
27
-
28
- const issue = selectNextIssue();
29
- if (!issue) {
30
- renderOutput(isJson, { status: 'success', issue: null }, () => {
31
- console.log('No open issues available. All work is complete or the backlog is empty.');
32
- });
33
- return 0;
34
- }
35
-
36
- const updated = claimIssue(issue.id);
37
- const envelope = { status: 'success', issue: serializeIssue(updated) };
38
-
39
- renderOutput(isJson, envelope, () => {
40
- console.log('Working on next issue:');
41
- console.log(` ID: #${updated.id}`);
42
- console.log(` Title: ${updated.title}`);
43
- console.log(` Priority: ${updated.priority}`);
44
- console.log(` Status: ${updated.status}`);
45
- console.log(` Attempts: ${updated.attemptNum}`);
46
- console.log(` Created: ${formatTimestamp(updated.createdAt)}`);
47
- if (updated.description) {
48
- console.log(` Description: ${updated.description}`);
49
- }
50
- });
51
-
52
- return 0;
53
- }