airgen-cli 0.20.2 → 0.20.4
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/dist/commands/requirements.js +11 -4
- package/dist/commands/traceability.js +7 -1
- package/dist/resolve.d.ts +6 -3
- package/dist/resolve.js +14 -10
- package/package.json +1 -1
|
@@ -139,8 +139,10 @@ export function registerRequirementCommands(program, client) {
|
|
|
139
139
|
.option("--idempotency-key <key>", "Prevent duplicates on retry — returns existing if key was already used")
|
|
140
140
|
.action(async (tenant, projectKey, opts) => {
|
|
141
141
|
if (!opts.section && !opts.document) {
|
|
142
|
-
console.error("
|
|
143
|
-
console.error("
|
|
142
|
+
console.error("Error: --section or --document is required. Without it, the requirement gets a project-level ref");
|
|
143
|
+
console.error(" (e.g., REQ-SEEMERGENCYDIESEL...-001) that breaks delete/reassign on long project slugs.");
|
|
144
|
+
console.error(" Use: airgen docs sections list <tenant> <project> <document> to find section IDs.");
|
|
145
|
+
process.exit(1);
|
|
144
146
|
}
|
|
145
147
|
const data = await client.post("/requirements", {
|
|
146
148
|
tenant,
|
|
@@ -199,8 +201,8 @@ export function registerRequirementCommands(program, client) {
|
|
|
199
201
|
if (opts.section)
|
|
200
202
|
body.sectionId = opts.section;
|
|
201
203
|
if (opts.addTags || opts.removeTags) {
|
|
202
|
-
// Read-modify-write for add/remove tags
|
|
203
|
-
const existing = await client.get(`/requirements/${tenant}/${project}/${encodeURIComponent(
|
|
204
|
+
// Read-modify-write for add/remove tags
|
|
205
|
+
const existing = await client.get(`/requirements/${tenant}/${project}/${encodeURIComponent(resolvedId)}`);
|
|
204
206
|
let currentTags = existing.record?.tags ?? [];
|
|
205
207
|
if (opts.addTags) {
|
|
206
208
|
const toAdd = opts.addTags.split(",").map(t => t.trim());
|
|
@@ -378,6 +380,11 @@ export function registerRequirementCommands(program, client) {
|
|
|
378
380
|
skipped++;
|
|
379
381
|
continue;
|
|
380
382
|
}
|
|
383
|
+
if (!item.document && !item.documentSlug && !item.section && !item.sectionId) {
|
|
384
|
+
console.error(` [${i}] Skipped: missing document/section (would create homeless requirement)`);
|
|
385
|
+
skipped++;
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
381
388
|
if (opts.dryRun) {
|
|
382
389
|
console.log(` [dry-run] ${truncate(text, 80)}`);
|
|
383
390
|
created++;
|
|
@@ -211,6 +211,12 @@ export function registerTraceabilityCommands(program, client) {
|
|
|
211
211
|
try {
|
|
212
212
|
// Delete old link, create reversed
|
|
213
213
|
await client.delete(`/trace-links/${tenant}/${project}/${link.id}`);
|
|
214
|
+
}
|
|
215
|
+
catch {
|
|
216
|
+
console.error(` Skipped: link ${link.id} not deletable (may be an embedded linkset link)`);
|
|
217
|
+
continue;
|
|
218
|
+
}
|
|
219
|
+
try {
|
|
214
220
|
await client.post("/trace-links", {
|
|
215
221
|
tenant, projectKey: project,
|
|
216
222
|
sourceRequirementId: link.targetRequirementId,
|
|
@@ -222,7 +228,7 @@ export function registerTraceabilityCommands(program, client) {
|
|
|
222
228
|
console.log(` Fixed: reversed to ${targetRef(link)} --${link.linkType}--> ${sourceRef(link)}`);
|
|
223
229
|
}
|
|
224
230
|
catch (err) {
|
|
225
|
-
console.error(`
|
|
231
|
+
console.error(` Delete succeeded but reverse create failed: ${err.message}`);
|
|
226
232
|
}
|
|
227
233
|
}
|
|
228
234
|
}
|
package/dist/resolve.d.ts
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Resolve any requirement identifier to
|
|
2
|
+
* Resolve any requirement identifier to a ref suitable for API paths.
|
|
3
3
|
*
|
|
4
|
-
* Accepts: full ID, ref
|
|
5
|
-
*
|
|
4
|
+
* Accepts: full composite ID (tenant:project:REF), ref (STK-REQ-001),
|
|
5
|
+
* short ID, or hashId.
|
|
6
|
+
*
|
|
7
|
+
* Returns the ref string (e.g. STK-REQ-001) — NOT the full composite ID,
|
|
8
|
+
* since the API route already includes tenant and project in the path.
|
|
6
9
|
*/
|
|
7
10
|
import type { AirgenClient } from "./client.js";
|
|
8
11
|
export declare function resolveRequirementId(client: AirgenClient, tenant: string, project: string, identifier: string): Promise<string>;
|
package/dist/resolve.js
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Resolve any requirement identifier to
|
|
2
|
+
* Resolve any requirement identifier to a ref suitable for API paths.
|
|
3
3
|
*
|
|
4
|
-
* Accepts: full ID, ref
|
|
5
|
-
*
|
|
4
|
+
* Accepts: full composite ID (tenant:project:REF), ref (STK-REQ-001),
|
|
5
|
+
* short ID, or hashId.
|
|
6
|
+
*
|
|
7
|
+
* Returns the ref string (e.g. STK-REQ-001) — NOT the full composite ID,
|
|
8
|
+
* since the API route already includes tenant and project in the path.
|
|
6
9
|
*/
|
|
7
10
|
export async function resolveRequirementId(client, tenant, project, identifier) {
|
|
8
|
-
//
|
|
11
|
+
// Full composite ID (tenant:project:REF) — extract the ref part
|
|
9
12
|
if (identifier.includes(":")) {
|
|
10
|
-
|
|
13
|
+
const parts = identifier.split(":");
|
|
14
|
+
return parts[parts.length - 1];
|
|
11
15
|
}
|
|
12
16
|
// Try as ref first (GET /requirements/{tenant}/{project}/{ref})
|
|
13
17
|
try {
|
|
14
|
-
const data = await client.get(`/requirements/${tenant}/${project}/${identifier}`);
|
|
15
|
-
if (data.record?.
|
|
16
|
-
return data.record.
|
|
18
|
+
const data = await client.get(`/requirements/${tenant}/${project}/${encodeURIComponent(identifier)}`);
|
|
19
|
+
if (data.record?.ref)
|
|
20
|
+
return data.record.ref;
|
|
17
21
|
}
|
|
18
22
|
catch {
|
|
19
23
|
// Not found by ref — continue
|
|
@@ -27,10 +31,10 @@ export async function resolveRequirementId(client, tenant, project, identifier)
|
|
|
27
31
|
for (const r of reqs) {
|
|
28
32
|
// Match by short ID (the REQ-XXX part of tenant:project:REQ-XXX)
|
|
29
33
|
if (r.id?.endsWith(`:${identifier}`))
|
|
30
|
-
return r.
|
|
34
|
+
return r.ref ?? identifier;
|
|
31
35
|
// Match by hashId
|
|
32
36
|
if (r.hashId === identifier)
|
|
33
|
-
return r.
|
|
37
|
+
return r.ref ?? identifier;
|
|
34
38
|
}
|
|
35
39
|
if (page >= (data.meta?.totalPages ?? 1))
|
|
36
40
|
break;
|