@braingrid/cli 0.2.17 → 0.2.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/CHANGELOG.md +34 -0
- package/dist/cli.js +90 -18
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,40 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.19] - 2025-12-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Pagination options for task commands**
|
|
15
|
+
- Added `--page` and `--limit` options to `task list` and `task summary` commands
|
|
16
|
+
- Consistent with existing pagination options on `requirement list`
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **has_more pagination warnings**
|
|
21
|
+
- Task and requirement list commands now show a warning when more items exist beyond current page
|
|
22
|
+
- Warning message: "⚠️ More tasks/requirements exist. Use --limit to see more."
|
|
23
|
+
- `getCurrentTask` auto-detection warns if results may be incomplete due to pagination
|
|
24
|
+
|
|
25
|
+
- **Status line uses higher limit**
|
|
26
|
+
- Claude Code status line script now fetches up to 100 tasks for accurate counts
|
|
27
|
+
- Ensures task progress display `[completed/total]` is accurate for larger requirements
|
|
28
|
+
|
|
29
|
+
## [0.2.18] - 2025-12-17
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
|
|
33
|
+
- **Current task auto-detection**
|
|
34
|
+
- `task show` now works without a task ID - automatically detects the current task
|
|
35
|
+
- `task update` now works without a task ID - updates the current task
|
|
36
|
+
- Current task is determined by: first IN_PROGRESS task, or first PLANNED task if none in progress
|
|
37
|
+
- `task delete` still requires explicit task ID for safety
|
|
38
|
+
|
|
39
|
+
- **Status line shows current task**
|
|
40
|
+
- Claude Code status line now displays: `BrainGrid: PROJ-X > REQ-Y > TASK-Z [completed/total]`
|
|
41
|
+
- Shows the current task being worked on alongside progress count
|
|
42
|
+
- Automatically updates as tasks are completed
|
|
43
|
+
|
|
10
44
|
## [0.2.17] - 2025-12-17
|
|
11
45
|
|
|
12
46
|
### Added
|
package/dist/cli.js
CHANGED
|
@@ -422,7 +422,7 @@ import axios3, { AxiosError as AxiosError2 } from "axios";
|
|
|
422
422
|
|
|
423
423
|
// src/build-config.ts
|
|
424
424
|
var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
|
|
425
|
-
var CLI_VERSION = true ? "0.2.
|
|
425
|
+
var CLI_VERSION = true ? "0.2.19" : "0.0.0-test";
|
|
426
426
|
var PRODUCTION_CONFIG = {
|
|
427
427
|
apiUrl: "https://app.braingrid.ai",
|
|
428
428
|
workosAuthUrl: "https://auth.braingrid.ai",
|
|
@@ -3914,6 +3914,9 @@ async function handleRequirementList(opts) {
|
|
|
3914
3914
|
break;
|
|
3915
3915
|
}
|
|
3916
3916
|
}
|
|
3917
|
+
if (response.pagination?.has_more) {
|
|
3918
|
+
output += "\n" + chalk7.yellow("\u26A0\uFE0F More requirements exist. Use --limit to see more.");
|
|
3919
|
+
}
|
|
3917
3920
|
return {
|
|
3918
3921
|
success: true,
|
|
3919
3922
|
message: output,
|
|
@@ -4518,6 +4521,29 @@ function getServices3() {
|
|
|
4518
4521
|
const taskService = new TaskService(config.apiUrl, auth);
|
|
4519
4522
|
return { taskService, auth };
|
|
4520
4523
|
}
|
|
4524
|
+
async function getCurrentTask(taskService, projectId, requirementId) {
|
|
4525
|
+
const response = await taskService.listTasks(projectId, requirementId);
|
|
4526
|
+
const inProgress = response.tasks.find((t) => t.status === "IN_PROGRESS");
|
|
4527
|
+
if (inProgress) {
|
|
4528
|
+
const warning = response.pagination?.has_more ? "Note: More tasks exist beyond current page." : void 0;
|
|
4529
|
+
return { success: true, taskId: inProgress.number, warning };
|
|
4530
|
+
}
|
|
4531
|
+
const planned = response.tasks.find((t) => t.status === "PLANNED");
|
|
4532
|
+
if (planned) {
|
|
4533
|
+
const warning = response.pagination?.has_more ? "Note: More tasks exist beyond current page." : void 0;
|
|
4534
|
+
return { success: true, taskId: planned.number, warning };
|
|
4535
|
+
}
|
|
4536
|
+
if (response.pagination?.has_more) {
|
|
4537
|
+
return {
|
|
4538
|
+
success: false,
|
|
4539
|
+
error: "No active task found in current page. More tasks exist - use --limit to fetch more."
|
|
4540
|
+
};
|
|
4541
|
+
}
|
|
4542
|
+
return {
|
|
4543
|
+
success: false,
|
|
4544
|
+
error: "No active task found. All tasks are completed or cancelled."
|
|
4545
|
+
};
|
|
4546
|
+
}
|
|
4521
4547
|
async function handleTaskList(opts) {
|
|
4522
4548
|
let stopSpinner = null;
|
|
4523
4549
|
try {
|
|
@@ -4546,7 +4572,10 @@ async function handleTaskList(opts) {
|
|
|
4546
4572
|
}
|
|
4547
4573
|
const requirementId = requirementResult.requirementId;
|
|
4548
4574
|
stopSpinner = showSpinner("Loading tasks", chalk8.gray);
|
|
4549
|
-
const response = await taskService.listTasks(projectId, requirementId
|
|
4575
|
+
const response = await taskService.listTasks(projectId, requirementId, {
|
|
4576
|
+
page: opts.page ? parseInt(opts.page, 10) : 1,
|
|
4577
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 20
|
|
4578
|
+
});
|
|
4550
4579
|
stopSpinner();
|
|
4551
4580
|
stopSpinner = null;
|
|
4552
4581
|
if (response.tasks.length === 0) {
|
|
@@ -4560,12 +4589,15 @@ async function handleTaskList(opts) {
|
|
|
4560
4589
|
const requirementShortId = opts.requirement || requirementId;
|
|
4561
4590
|
const format = opts.format || "markdown";
|
|
4562
4591
|
const config = getConfig();
|
|
4563
|
-
|
|
4592
|
+
let output = formatTasksListOutput(response.tasks, format, true, {
|
|
4564
4593
|
requirementId,
|
|
4565
4594
|
projectShortId,
|
|
4566
4595
|
requirementShortId,
|
|
4567
4596
|
apiUrl: config.apiUrl
|
|
4568
4597
|
});
|
|
4598
|
+
if (response.pagination?.has_more) {
|
|
4599
|
+
output += "\n" + chalk8.yellow("\u26A0\uFE0F More tasks exist. Use --limit to see more.");
|
|
4600
|
+
}
|
|
4569
4601
|
return {
|
|
4570
4602
|
success: true,
|
|
4571
4603
|
message: output,
|
|
@@ -4609,7 +4641,10 @@ async function handleTaskSummary(opts) {
|
|
|
4609
4641
|
}
|
|
4610
4642
|
const requirementId = requirementResult.requirementId;
|
|
4611
4643
|
stopSpinner = showSpinner("Loading tasks", chalk8.gray);
|
|
4612
|
-
const response = await taskService.listTasks(projectId, requirementId
|
|
4644
|
+
const response = await taskService.listTasks(projectId, requirementId, {
|
|
4645
|
+
page: opts.page ? parseInt(opts.page, 10) : 1,
|
|
4646
|
+
limit: opts.limit ? parseInt(opts.limit, 10) : 20
|
|
4647
|
+
});
|
|
4613
4648
|
stopSpinner();
|
|
4614
4649
|
stopSpinner = null;
|
|
4615
4650
|
if (response.tasks.length === 0) {
|
|
@@ -4622,12 +4657,15 @@ async function handleTaskSummary(opts) {
|
|
|
4622
4657
|
const projectShortId = projectId;
|
|
4623
4658
|
const requirementShortId = opts.requirement || requirementId;
|
|
4624
4659
|
const config = getConfig();
|
|
4625
|
-
|
|
4660
|
+
let output = formatTasksListOutput(response.tasks, "table", false, {
|
|
4626
4661
|
requirementId,
|
|
4627
4662
|
projectShortId,
|
|
4628
4663
|
requirementShortId,
|
|
4629
4664
|
apiUrl: config.apiUrl
|
|
4630
4665
|
});
|
|
4666
|
+
if (response.pagination?.has_more) {
|
|
4667
|
+
output += "\n" + chalk8.yellow("\u26A0\uFE0F More tasks exist. Use --limit to see more.");
|
|
4668
|
+
}
|
|
4631
4669
|
return {
|
|
4632
4670
|
success: true,
|
|
4633
4671
|
message: output,
|
|
@@ -4679,7 +4717,21 @@ async function handleTaskShow(id, opts) {
|
|
|
4679
4717
|
};
|
|
4680
4718
|
}
|
|
4681
4719
|
const requirementId = requirementResult.requirementId;
|
|
4682
|
-
|
|
4720
|
+
let taskId;
|
|
4721
|
+
let taskWarning;
|
|
4722
|
+
if (id) {
|
|
4723
|
+
taskId = normalizeTaskId(id);
|
|
4724
|
+
} else {
|
|
4725
|
+
const currentTask = await getCurrentTask(taskService, projectId, requirementId);
|
|
4726
|
+
if (!currentTask.success) {
|
|
4727
|
+
return {
|
|
4728
|
+
success: false,
|
|
4729
|
+
message: chalk8.red(`\u274C ${currentTask.error}`)
|
|
4730
|
+
};
|
|
4731
|
+
}
|
|
4732
|
+
taskId = currentTask.taskId;
|
|
4733
|
+
taskWarning = currentTask.warning;
|
|
4734
|
+
}
|
|
4683
4735
|
const config = getConfig();
|
|
4684
4736
|
stopSpinner = showSpinner("Loading task", chalk8.gray);
|
|
4685
4737
|
const task2 = await taskService.getTask(projectId, requirementId, taskId);
|
|
@@ -4713,6 +4765,9 @@ async function handleTaskShow(id, opts) {
|
|
|
4713
4765
|
break;
|
|
4714
4766
|
}
|
|
4715
4767
|
}
|
|
4768
|
+
if (taskWarning) {
|
|
4769
|
+
output += "\n" + chalk8.yellow(`\u26A0\uFE0F ${taskWarning}`);
|
|
4770
|
+
}
|
|
4716
4771
|
return {
|
|
4717
4772
|
success: true,
|
|
4718
4773
|
message: output,
|
|
@@ -4799,13 +4854,13 @@ async function handleTaskUpdate(id, opts) {
|
|
|
4799
4854
|
message: chalk8.red("\u274C Not authenticated. Please run `braingrid login` first.")
|
|
4800
4855
|
};
|
|
4801
4856
|
}
|
|
4802
|
-
if (!opts
|
|
4857
|
+
if (!opts?.status && !opts?.title) {
|
|
4803
4858
|
return {
|
|
4804
4859
|
success: false,
|
|
4805
4860
|
message: chalk8.red("\u274C Please provide at least one field to update (--status or --title)")
|
|
4806
4861
|
};
|
|
4807
4862
|
}
|
|
4808
|
-
const workspace = await workspaceManager.getProject(opts
|
|
4863
|
+
const workspace = await workspaceManager.getProject(opts?.project);
|
|
4809
4864
|
if (!workspace.success) {
|
|
4810
4865
|
return {
|
|
4811
4866
|
success: false,
|
|
@@ -4813,7 +4868,7 @@ async function handleTaskUpdate(id, opts) {
|
|
|
4813
4868
|
};
|
|
4814
4869
|
}
|
|
4815
4870
|
const projectId = workspace.projectId;
|
|
4816
|
-
const requirementResult = await workspaceManager.getRequirement(opts
|
|
4871
|
+
const requirementResult = await workspaceManager.getRequirement(opts?.requirement);
|
|
4817
4872
|
if (!requirementResult.success) {
|
|
4818
4873
|
return {
|
|
4819
4874
|
success: false,
|
|
@@ -4821,23 +4876,40 @@ async function handleTaskUpdate(id, opts) {
|
|
|
4821
4876
|
};
|
|
4822
4877
|
}
|
|
4823
4878
|
const requirementId = requirementResult.requirementId;
|
|
4824
|
-
|
|
4879
|
+
let taskId;
|
|
4880
|
+
let taskWarning;
|
|
4881
|
+
if (id) {
|
|
4882
|
+
taskId = normalizeTaskId(id);
|
|
4883
|
+
} else {
|
|
4884
|
+
const currentTask = await getCurrentTask(taskService, projectId, requirementId);
|
|
4885
|
+
if (!currentTask.success) {
|
|
4886
|
+
return {
|
|
4887
|
+
success: false,
|
|
4888
|
+
message: chalk8.red(`\u274C ${currentTask.error}`)
|
|
4889
|
+
};
|
|
4890
|
+
}
|
|
4891
|
+
taskId = currentTask.taskId;
|
|
4892
|
+
taskWarning = currentTask.warning;
|
|
4893
|
+
}
|
|
4825
4894
|
const config = getConfig();
|
|
4826
4895
|
stopSpinner = showSpinner("Updating task", chalk8.gray);
|
|
4827
4896
|
const task2 = await taskService.updateTask(projectId, requirementId, taskId, {
|
|
4828
|
-
status: opts
|
|
4829
|
-
title: opts
|
|
4897
|
+
status: opts?.status,
|
|
4898
|
+
title: opts?.title
|
|
4830
4899
|
});
|
|
4831
4900
|
stopSpinner();
|
|
4832
4901
|
stopSpinner = null;
|
|
4833
|
-
|
|
4902
|
+
let output = formatTaskOutput(task2, {
|
|
4834
4903
|
showContent: true,
|
|
4835
4904
|
successMessage: `Updated task ${task2.number}`,
|
|
4836
4905
|
apiUrl: config.apiUrl,
|
|
4837
4906
|
projectShortId: projectId,
|
|
4838
|
-
requirementShortId: opts
|
|
4907
|
+
requirementShortId: opts?.requirement || requirementId,
|
|
4839
4908
|
requirementId
|
|
4840
4909
|
});
|
|
4910
|
+
if (taskWarning) {
|
|
4911
|
+
output += "\n" + chalk8.yellow(`\u26A0\uFE0F ${taskWarning}`);
|
|
4912
|
+
}
|
|
4841
4913
|
return {
|
|
4842
4914
|
success: true,
|
|
4843
4915
|
message: output,
|
|
@@ -7168,21 +7240,21 @@ requirement.command("build [id]").description(
|
|
|
7168
7240
|
}
|
|
7169
7241
|
});
|
|
7170
7242
|
var task = program.command("task").description("Manage tasks");
|
|
7171
|
-
task.command("list").description("List tasks for a requirement").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--format <format>", "output format (table, json, xml, markdown)", "markdown").action(async (opts) => {
|
|
7243
|
+
task.command("list").description("List tasks for a requirement").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--format <format>", "output format (table, json, xml, markdown)", "markdown").option("--page <page>", "page number for pagination", "1").option("--limit <limit>", "number of tasks per page", "20").action(async (opts) => {
|
|
7172
7244
|
const result = await handleTaskList(opts);
|
|
7173
7245
|
console.log(result.message);
|
|
7174
7246
|
if (!result.success) {
|
|
7175
7247
|
process.exit(1);
|
|
7176
7248
|
}
|
|
7177
7249
|
});
|
|
7178
|
-
task.command("summary").description("Show task summary table (quick overview without content)").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").action(async (opts) => {
|
|
7250
|
+
task.command("summary").description("Show task summary table (quick overview without content)").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--page <page>", "page number for pagination", "1").option("--limit <limit>", "number of tasks per page", "20").action(async (opts) => {
|
|
7179
7251
|
const result = await handleTaskSummary(opts);
|
|
7180
7252
|
console.log(result.message);
|
|
7181
7253
|
if (!result.success) {
|
|
7182
7254
|
process.exit(1);
|
|
7183
7255
|
}
|
|
7184
7256
|
});
|
|
7185
|
-
task.command("show
|
|
7257
|
+
task.command("show [id]").description("Show task details (auto-detects current task if not provided)").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--format <format>", "output format (table, json, xml, markdown)", "table").action(async (id, opts) => {
|
|
7186
7258
|
const result = await handleTaskShow(id, opts);
|
|
7187
7259
|
console.log(result.message);
|
|
7188
7260
|
if (!result.success) {
|
|
@@ -7196,7 +7268,7 @@ task.command("create").description("Create a new task").option("-r, --requiremen
|
|
|
7196
7268
|
process.exit(1);
|
|
7197
7269
|
}
|
|
7198
7270
|
});
|
|
7199
|
-
task.command("update
|
|
7271
|
+
task.command("update [id]").description("Update task (auto-detects current task if not provided)").option("-r, --requirement <id>", "requirement ID (REQ-456, auto-detects project if initialized)").option("-p, --project <id>", "project ID (PROJ-123, optional if project is initialized)").option("--status <status>", "new status (PLANNED, IN_PROGRESS, COMPLETED, CANCELLED)").option("--title <title>", "new task title").action(async (id, opts) => {
|
|
7200
7272
|
const result = await handleTaskUpdate(id, opts);
|
|
7201
7273
|
console.log(result.message);
|
|
7202
7274
|
if (!result.success) {
|