airgen-cli 0.1.3 → 0.1.5

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.
@@ -1,6 +1,8 @@
1
1
  import { output, printTable, isJsonMode, truncate } from "../output.js";
2
2
  const IMPL_TAG_PREFIX = "impl:";
3
3
  const IMPL_STATUSES = ["not_started", "in_progress", "implemented", "verified", "blocked"];
4
+ const PAGE_SIZE = 100;
5
+ const MAX_PAGES = 50;
4
6
  function getImplStatus(tags) {
5
7
  if (!tags)
6
8
  return null;
@@ -10,6 +12,21 @@ function getImplStatus(tags) {
10
12
  const status = implTag.slice(IMPL_TAG_PREFIX.length);
11
13
  return IMPL_STATUSES.includes(status) ? status : null;
12
14
  }
15
+ async function fetchAllRequirements(client, tenant, project) {
16
+ const all = [];
17
+ for (let page = 1; page <= MAX_PAGES; page++) {
18
+ const data = await client.get(`/requirements/${tenant}/${project}`, {
19
+ page: String(page),
20
+ limit: String(PAGE_SIZE),
21
+ });
22
+ const items = data.data ?? [];
23
+ all.push(...items);
24
+ const totalPages = data.meta?.totalPages ?? 1;
25
+ if (page >= totalPages)
26
+ break;
27
+ }
28
+ return all.filter(r => !r.deleted && !r.deletedAt);
29
+ }
13
30
  export function registerReportCommands(program, client) {
14
31
  const cmd = program.command("reports").alias("report").description("Project reports");
15
32
  cmd
@@ -44,10 +61,8 @@ export function registerReportCommands(program, client) {
44
61
  .description("Quality score summary")
45
62
  .argument("<tenant>", "Tenant slug")
46
63
  .argument("<project>", "Project slug")
47
- .option("-l, --limit <n>", "Max requirements to fetch", "100")
48
- .action(async (tenant, project, opts) => {
49
- const data = await client.get(`/requirements/${tenant}/${project}`, { page: "1", limit: opts.limit });
50
- const reqs = data.data ?? [];
64
+ .action(async (tenant, project) => {
65
+ const reqs = await fetchAllRequirements(client, tenant, project);
51
66
  const scored = reqs.filter(r => r.qaScore != null);
52
67
  const avg = scored.length > 0
53
68
  ? scored.reduce((sum, r) => sum + (r.qaScore ?? 0), 0) / scored.length
@@ -72,13 +87,11 @@ export function registerReportCommands(program, client) {
72
87
  });
73
88
  cmd
74
89
  .command("compliance")
75
- .description("Compliance status summary")
90
+ .description("Compliance and implementation status summary")
76
91
  .argument("<tenant>", "Tenant slug")
77
92
  .argument("<project>", "Project slug")
78
- .option("-l, --limit <n>", "Max requirements to fetch", "100")
79
- .action(async (tenant, project, opts) => {
80
- const data = await client.get(`/requirements/${tenant}/${project}`, { page: "1", limit: opts.limit });
81
- const reqs = data.data ?? [];
93
+ .action(async (tenant, project) => {
94
+ const reqs = await fetchAllRequirements(client, tenant, project);
82
95
  // Compliance status
83
96
  const compCounts = {};
84
97
  for (const r of reqs) {
@@ -98,9 +111,10 @@ export function registerReportCommands(program, client) {
98
111
  implCounts["unset"]++;
99
112
  }
100
113
  if (isJsonMode()) {
101
- output({ compliance: compCounts, implementation: implCounts });
114
+ output({ total: reqs.length, compliance: compCounts, implementation: implCounts });
102
115
  }
103
116
  else {
117
+ console.log(`Total requirements: ${reqs.length}\n`);
104
118
  console.log("Compliance Status:");
105
119
  printTable(["Status", "Count"], Object.entries(compCounts).map(([k, v]) => [k, String(v)]));
106
120
  console.log("\nImplementation Status:");
@@ -112,13 +126,11 @@ export function registerReportCommands(program, client) {
112
126
  .description("Find requirements with no trace links")
113
127
  .argument("<tenant>", "Tenant slug")
114
128
  .argument("<project>", "Project slug")
115
- .option("-l, --limit <n>", "Max requirements to fetch", "100")
116
- .action(async (tenant, project, opts) => {
117
- const [reqData, linkData] = await Promise.all([
118
- client.get(`/requirements/${tenant}/${project}`, { page: "1", limit: opts.limit }),
129
+ .action(async (tenant, project) => {
130
+ const [reqs, linkData] = await Promise.all([
131
+ fetchAllRequirements(client, tenant, project),
119
132
  client.get(`/trace-links/${tenant}/${project}`),
120
133
  ]);
121
- const reqs = reqData.data ?? [];
122
134
  const links = linkData.links ?? [];
123
135
  const linked = new Set();
124
136
  for (const l of links) {
package/dist/index.js CHANGED
@@ -1,7 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ import { createRequire } from "node:module";
2
3
  import { Command } from "commander";
3
4
  import { AirgenClient } from "./client.js";
4
5
  import { loadConfig } from "./config.js";
6
+ const require = createRequire(import.meta.url);
7
+ const { version } = require("../package.json");
5
8
  import { setJsonMode } from "./output.js";
6
9
  import { registerTenantCommands } from "./commands/tenants.js";
7
10
  import { registerProjectCommands } from "./commands/projects.js";
@@ -39,7 +42,7 @@ const clientProxy = new Proxy({}, {
39
42
  program
40
43
  .name("airgen")
41
44
  .description("AIRGen CLI — requirements engineering from the command line")
42
- .version("0.1.0")
45
+ .version(version)
43
46
  .option("--json", "Output as JSON")
44
47
  .hook("preAction", (_thisCommand, actionCommand) => {
45
48
  let cmd = actionCommand;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "airgen-cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "description": "AIRGen CLI — requirements engineering from the command line",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -8,7 +8,8 @@
8
8
  "airgen": "dist/index.js"
9
9
  },
10
10
  "files": [
11
- "dist"
11
+ "dist",
12
+ "package.json"
12
13
  ],
13
14
  "scripts": {
14
15
  "build": "tsc -p tsconfig.json",