@braingrid/cli 0.2.26 → 0.2.27
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 +10 -0
- package/dist/cli.js +78 -8
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,16 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.2.27] - 2025-01-27
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Requirement tagging support**
|
|
15
|
+
- New `--tags` option for `requirement create` and `specify` commands
|
|
16
|
+
- Accepts comma-separated tags (max 5 per requirement)
|
|
17
|
+
- Tags are validated, trimmed, and empty values filtered
|
|
18
|
+
- Tags displayed in all output formats (table, markdown, XML, JSON)
|
|
19
|
+
|
|
10
20
|
## [0.2.26] - 2025-01-20
|
|
11
21
|
|
|
12
22
|
### Added
|
package/dist/cli.js
CHANGED
|
@@ -25,7 +25,7 @@ import axios from "axios";
|
|
|
25
25
|
|
|
26
26
|
// src/build-config.ts
|
|
27
27
|
var BUILD_ENV = true ? "production" : process.env.NODE_ENV === "test" ? "development" : "production";
|
|
28
|
-
var CLI_VERSION = true ? "0.2.
|
|
28
|
+
var CLI_VERSION = true ? "0.2.27" : "0.0.0-test";
|
|
29
29
|
var PRODUCTION_CONFIG = {
|
|
30
30
|
apiUrl: "https://app.braingrid.ai",
|
|
31
31
|
workosAuthUrl: "https://auth.braingrid.ai",
|
|
@@ -2744,6 +2744,11 @@ function formatRequirementOutput(requirement2, options) {
|
|
|
2744
2744
|
}
|
|
2745
2745
|
message += `${chalk5.bold("Status:")} ${requirement2.status}
|
|
2746
2746
|
`;
|
|
2747
|
+
if (requirement2.tags && requirement2.tags.length > 0) {
|
|
2748
|
+
const tagNames = requirement2.tags.map((tag) => tag.name).join(", ");
|
|
2749
|
+
message += `${chalk5.bold("Tags:")} ${tagNames}
|
|
2750
|
+
`;
|
|
2751
|
+
}
|
|
2747
2752
|
if (requirement2.assignee) {
|
|
2748
2753
|
const assigneeName = requirement2.assignee.first_name || requirement2.assignee.last_name ? `${requirement2.assignee.first_name || ""} ${requirement2.assignee.last_name || ""}`.trim() : requirement2.assignee.email;
|
|
2749
2754
|
message += `${chalk5.bold("Assigned to:")} ${assigneeName} (${requirement2.assignee.email})
|
|
@@ -2890,15 +2895,16 @@ function formatRequirementListMarkdown(requirements, pagination) {
|
|
|
2890
2895
|
md += "_No requirements found._\n";
|
|
2891
2896
|
return md;
|
|
2892
2897
|
}
|
|
2893
|
-
md += "| Short ID | Status | Name | Branch | Progress |\n";
|
|
2894
|
-
md += "
|
|
2898
|
+
md += "| Short ID | Status | Name | Branch | Tags | Progress |\n";
|
|
2899
|
+
md += "|----------|--------|------|--------|------|----------|\n";
|
|
2895
2900
|
for (const req of requirements) {
|
|
2896
2901
|
const shortId = req.short_id || req.id.slice(0, 11);
|
|
2897
2902
|
const status = req.status;
|
|
2898
2903
|
const name = req.name;
|
|
2899
2904
|
const branch = req.branch || "N/A";
|
|
2905
|
+
const tags = req.tags && req.tags.length > 0 ? req.tags.map((t) => t.name).join(", ") : "-";
|
|
2900
2906
|
const progress = req.task_progress ? `${req.task_progress.progress_percentage}%` : "N/A";
|
|
2901
|
-
md += `| ${shortId} | ${status} | ${name} | ${branch} | ${progress} |
|
|
2907
|
+
md += `| ${shortId} | ${status} | ${name} | ${branch} | ${tags} | ${progress} |
|
|
2902
2908
|
`;
|
|
2903
2909
|
}
|
|
2904
2910
|
if (pagination) {
|
|
@@ -2971,6 +2977,15 @@ function formatRequirementListXml(requirements, pagination) {
|
|
|
2971
2977
|
`;
|
|
2972
2978
|
xml += " </assignee>\n";
|
|
2973
2979
|
}
|
|
2980
|
+
if (req.tags && req.tags.length > 0) {
|
|
2981
|
+
xml += ` <tags count="${req.tags.length}">
|
|
2982
|
+
`;
|
|
2983
|
+
for (const tag of req.tags) {
|
|
2984
|
+
xml += ` <tag>${escapeXml(tag.name)}</tag>
|
|
2985
|
+
`;
|
|
2986
|
+
}
|
|
2987
|
+
xml += " </tags>\n";
|
|
2988
|
+
}
|
|
2974
2989
|
xml += ` <created_at>${escapeXml(req.created_at)}</created_at>
|
|
2975
2990
|
`;
|
|
2976
2991
|
xml += ` <updated_at>${escapeXml(req.updated_at)}</updated_at>
|
|
@@ -3087,6 +3102,12 @@ function formatRequirementBuildMarkdown(requirement2, options) {
|
|
|
3087
3102
|
md += `**Status:** ${requirement2.status}
|
|
3088
3103
|
|
|
3089
3104
|
`;
|
|
3105
|
+
if (requirement2.tags && requirement2.tags.length > 0) {
|
|
3106
|
+
const tagNames = requirement2.tags.map((tag) => tag.name).join(", ");
|
|
3107
|
+
md += `**Tags:** ${tagNames}
|
|
3108
|
+
|
|
3109
|
+
`;
|
|
3110
|
+
}
|
|
3090
3111
|
if (requirement2.assignee) {
|
|
3091
3112
|
const assigneeName = requirement2.assignee.first_name || requirement2.assignee.last_name ? `${requirement2.assignee.first_name || ""} ${requirement2.assignee.last_name || ""}`.trim() : requirement2.assignee.email;
|
|
3092
3113
|
md += `**Assigned to:** ${assigneeName} (${requirement2.assignee.email})
|
|
@@ -3223,6 +3244,15 @@ function formatRequirementBuildXml(requirement2) {
|
|
|
3223
3244
|
xml += ` <branch>${escapeXml(requirement2.branch)}</branch>
|
|
3224
3245
|
`;
|
|
3225
3246
|
}
|
|
3247
|
+
if (requirement2.tags && requirement2.tags.length > 0) {
|
|
3248
|
+
xml += ` <tags count="${requirement2.tags.length}">
|
|
3249
|
+
`;
|
|
3250
|
+
for (const tag of requirement2.tags) {
|
|
3251
|
+
xml += ` <tag>${escapeXml(tag.name)}</tag>
|
|
3252
|
+
`;
|
|
3253
|
+
}
|
|
3254
|
+
xml += " </tags>\n";
|
|
3255
|
+
}
|
|
3226
3256
|
if (requirement2.assignee) {
|
|
3227
3257
|
xml += " <assignee>\n";
|
|
3228
3258
|
xml += ` <email>${escapeXml(requirement2.assignee.email)}</email>
|
|
@@ -3976,6 +4006,22 @@ var RequirementService = class {
|
|
|
3976
4006
|
}
|
|
3977
4007
|
};
|
|
3978
4008
|
|
|
4009
|
+
// src/utils/tag-validation.ts
|
|
4010
|
+
var MAX_TAGS = 5;
|
|
4011
|
+
function validateTags(tagsString) {
|
|
4012
|
+
if (!tagsString || tagsString.trim().length === 0) {
|
|
4013
|
+
return { valid: true, tags: [] };
|
|
4014
|
+
}
|
|
4015
|
+
const tags = tagsString.split(",").map((tag) => tag.trim()).filter((tag) => tag.length > 0);
|
|
4016
|
+
if (tags.length > MAX_TAGS) {
|
|
4017
|
+
return {
|
|
4018
|
+
valid: false,
|
|
4019
|
+
error: `Maximum ${MAX_TAGS} tags allowed`
|
|
4020
|
+
};
|
|
4021
|
+
}
|
|
4022
|
+
return { valid: true, tags };
|
|
4023
|
+
}
|
|
4024
|
+
|
|
3979
4025
|
// src/handlers/requirement.handlers.ts
|
|
3980
4026
|
function getServices2() {
|
|
3981
4027
|
const config = getConfig();
|
|
@@ -4203,11 +4249,23 @@ async function handleRequirementCreate(opts) {
|
|
|
4203
4249
|
};
|
|
4204
4250
|
}
|
|
4205
4251
|
}
|
|
4252
|
+
let validatedTags;
|
|
4253
|
+
if (opts.tags) {
|
|
4254
|
+
const tagResult = validateTags(opts.tags);
|
|
4255
|
+
if (!tagResult.valid) {
|
|
4256
|
+
return {
|
|
4257
|
+
success: false,
|
|
4258
|
+
message: chalk7.red(`\u274C ${tagResult.error}`)
|
|
4259
|
+
};
|
|
4260
|
+
}
|
|
4261
|
+
validatedTags = tagResult.tags;
|
|
4262
|
+
}
|
|
4206
4263
|
stopSpinner = showSpinner("Creating requirement", chalk7.gray);
|
|
4207
4264
|
const requirement2 = await requirementService.createProjectRequirement(projectId, {
|
|
4208
4265
|
name: opts.name,
|
|
4209
4266
|
content: opts.content || null,
|
|
4210
|
-
assigned_to: opts.assignedTo || null
|
|
4267
|
+
assigned_to: opts.assignedTo || null,
|
|
4268
|
+
tags: validatedTags
|
|
4211
4269
|
});
|
|
4212
4270
|
stopSpinner();
|
|
4213
4271
|
stopSpinner = null;
|
|
@@ -4280,9 +4338,21 @@ async function handleRequirementSpecify(opts) {
|
|
|
4280
4338
|
message: chalk7.red("\u274C Prompt must be no more than 5000 characters long")
|
|
4281
4339
|
};
|
|
4282
4340
|
}
|
|
4341
|
+
let validatedTags;
|
|
4342
|
+
if (opts.tags) {
|
|
4343
|
+
const tagResult = validateTags(opts.tags);
|
|
4344
|
+
if (!tagResult.valid) {
|
|
4345
|
+
return {
|
|
4346
|
+
success: false,
|
|
4347
|
+
message: chalk7.red(`\u274C ${tagResult.error}`)
|
|
4348
|
+
};
|
|
4349
|
+
}
|
|
4350
|
+
validatedTags = tagResult.tags;
|
|
4351
|
+
}
|
|
4283
4352
|
stopSpinner = showSpinner("Specifying requirement...");
|
|
4284
4353
|
const requirement2 = await requirementService.specifyRequirement(projectId, {
|
|
4285
|
-
prompt: opts.prompt
|
|
4354
|
+
prompt: opts.prompt,
|
|
4355
|
+
tags: validatedTags
|
|
4286
4356
|
});
|
|
4287
4357
|
stopSpinner();
|
|
4288
4358
|
stopSpinner = null;
|
|
@@ -7610,7 +7680,7 @@ program.command("update").description("Update BrainGrid CLI to the latest versio
|
|
|
7610
7680
|
program.command("specify").description("Create AI-refined requirement from prompt").option(
|
|
7611
7681
|
"-p, --project <id>",
|
|
7612
7682
|
"project ID (auto-detects from .braingrid/project.json if not provided)"
|
|
7613
|
-
).requiredOption("--prompt <prompt>", "requirement description (10-5000 characters)").option("--format <format>", "output format (table, json, xml, markdown)", "table").action(async (opts) => {
|
|
7683
|
+
).requiredOption("--prompt <prompt>", "requirement description (10-5000 characters)").option("-t, --tags <tags>", "comma-separated tags (max 5)").option("--format <format>", "output format (table, json, xml, markdown)", "table").action(async (opts) => {
|
|
7614
7684
|
const result = await handleRequirementSpecify(opts);
|
|
7615
7685
|
console.log(result.message);
|
|
7616
7686
|
if (!result.success) {
|
|
@@ -7695,7 +7765,7 @@ requirement.command("show [id]").description("Show requirement details (auto-det
|
|
|
7695
7765
|
requirement.command("create").description("Create a new requirement").option(
|
|
7696
7766
|
"-p, --project <id>",
|
|
7697
7767
|
"project ID (auto-detects from .braingrid/project.json if not provided)"
|
|
7698
|
-
).requiredOption("-n, --name <name>", "requirement name").option("-c, --content <content>", "requirement content/description").option("-a, --assigned-to <uuid>", "user UUID to assign the requirement to").action(async (opts) => {
|
|
7768
|
+
).requiredOption("-n, --name <name>", "requirement name").option("-c, --content <content>", "requirement content/description").option("-a, --assigned-to <uuid>", "user UUID to assign the requirement to").option("-t, --tags <tags>", "comma-separated tags (max 5)").action(async (opts) => {
|
|
7699
7769
|
const result = await handleRequirementCreate(opts);
|
|
7700
7770
|
console.log(result.message);
|
|
7701
7771
|
if (!result.success) {
|