@greenarmor/ges 1.5.2 → 1.5.3

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.
@@ -151,15 +151,15 @@ async function assignFinding(root, options) {
151
151
  errorOut("Governance record not found.");
152
152
  return;
153
153
  }
154
- const assignee = options.assignee || await input({ message: "Assignee name:" });
154
+ const assignee = options.assignee || await input({ message: "Assignee name (who will fix this):" });
155
155
  if (!assignee.trim()) {
156
- errorOut("Assignee name is required.");
156
+ errorOut("Assignee name is required.", "Please provide the name of the person responsible for this fix.");
157
157
  return;
158
158
  }
159
- const assigneeRole = options.assigneeRole || await input({ message: "Assignee role (optional):" });
160
- const notes = options.notes || await input({ message: "Notes (optional):" });
161
- const actorName = options.actor || await input({ message: "Your name (for audit trail):" });
162
- const actorRole = options.actorRole || await input({ message: "Your role (optional):" });
159
+ const assigneeRole = options.assigneeRole || await input({ message: "Assignee role (optional, e.g., 'Security Engineer'):", default: "" });
160
+ const notes = options.notes || await input({ message: "Notes (optional, e.g., 'Urgent — fix before release'):", default: "" });
161
+ const actorName = options.actor || await input({ message: "Your name (for audit trail):", default: "cli-user" });
162
+ const actorRole = options.actorRole || await input({ message: "Your role (optional):", default: "" });
163
163
  const assignment = createFixAssignment({
164
164
  finding_key: fkey,
165
165
  finding_rule_id: selectedFinding.ruleId,
@@ -1,7 +1,7 @@
1
1
  import { Command } from "commander";
2
2
  import { ensureGESInitialized } from "../utils/project.js";
3
3
  import { input, select } from "../utils/prompts.js";
4
- import { banner, divider, blank, success, info, kv, statusBadge, severityBadge, BOLD, DIM, GREEN, RED, YELLOW, GRAY, } from "../utils/ui.js";
4
+ import { banner, divider, blank, success, error, warn, info, kv, statusBadge, severityBadge, BOLD, DIM, GREEN, RED, YELLOW, GRAY, } from "../utils/ui.js";
5
5
  import { loadGovernanceRecords, createGovernanceRecord, addGovernanceRecord, findGovernanceRecord, setGovernanceApproval, addGovernanceEvidence, createEvidenceRef, verifyGovernanceRecord, deleteGovernanceRecord, setGovernanceRiskAssessment, setGovernancePolicyBasis, setGovernanceReviewCycle, setGovernanceDataInventory, setGovernanceComplianceLinks, setGovernanceCommittee, } from "@greenarmor/ges-core";
6
6
  import { recordActivity } from "@greenarmor/ges-core";
7
7
  const STATUS_BADGE = {
@@ -34,6 +34,91 @@ function printRecordSummary(record) {
34
34
  }
35
35
  export const governanceCommand = new Command("governance")
36
36
  .description("Manage governance approval provenance chains")
37
+ .action(async () => {
38
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
39
+ governanceCommand.outputHelp();
40
+ return;
41
+ }
42
+ banner("GESF Governance", "Provenance Chain Management");
43
+ let root;
44
+ try {
45
+ root = ensureGESInitialized();
46
+ }
47
+ catch {
48
+ error("GESF is not initialized.", "Run `ges init` first.");
49
+ blank();
50
+ return;
51
+ }
52
+ const records = loadGovernanceRecords(root);
53
+ if (records.length > 0) {
54
+ console.log(` ${BOLD("Existing Records")} ${GRAY(`(${records.length})`)}`);
55
+ records.forEach(r => printRecordSummary(r));
56
+ console.log("");
57
+ }
58
+ else {
59
+ warn("No governance records yet.", "Create one to start building a provenance chain.");
60
+ blank();
61
+ }
62
+ const action = await select({
63
+ message: "What would you like to do?",
64
+ choices: [
65
+ { name: `Create a new governance record ${DIM("— start a new approval chain")}`, value: "add" },
66
+ ...(records.length > 0 ? [
67
+ { name: `List all records ${DIM(`(${records.length} existing)`)}`, value: "list" },
68
+ { name: `Show a record's full provenance chain ${DIM("— all dimensions in detail")}`, value: "show" },
69
+ { name: `Verify a record's completeness ${DIM("— check all 8 dimensions")}`, value: "verify" },
70
+ { name: `Record an approval decision ${DIM("— who approved, under what authority")}`, value: "approve" },
71
+ { name: `Add an evidence reference ${DIM("— link to Jira, Confluence, etc.")}`, value: "evidence" },
72
+ { name: `Link a risk assessment ${DIM("— assessor, methodology, score")}`, value: "risk-assessment" },
73
+ { name: `Document the policy basis ${DIM("— which policy/standard applies")}`, value: "policy-basis" },
74
+ { name: `Set up a review cycle ${DIM("— when to re-review")}`, value: "review-cycle" },
75
+ { name: `Document data inventory ${DIM("— what personal data is processed")}`, value: "data-inventory" },
76
+ { name: `Record committee approval ${DIM("— formal committee sign-off")}`, value: "committee" },
77
+ { name: `Map compliance frameworks ${DIM("— GDPR, OWASP, etc.")}`, value: "compliance-links" },
78
+ { name: `Delete a record ${DIM("— permanently remove")}`, value: "delete" },
79
+ ] : []),
80
+ { name: `${YELLOW("Exit")} ${DIM("— return to terminal")}`, value: "exit" },
81
+ ],
82
+ });
83
+ if (action === "exit") {
84
+ blank();
85
+ return;
86
+ }
87
+ let cmd = `ges governance ${action}`;
88
+ if (["show", "verify", "approve", "evidence", "risk-assessment", "policy-basis", "review-cycle", "data-inventory", "committee", "compliance-links", "delete"].includes(action)) {
89
+ if (records.length === 0) {
90
+ error("No records to work with.", "Create one first with: ges governance add");
91
+ blank();
92
+ return;
93
+ }
94
+ if (records.length === 1) {
95
+ cmd += ` ${records[0].id}`;
96
+ }
97
+ else {
98
+ const recordChoice = await select({
99
+ message: "Select a record:",
100
+ choices: [
101
+ ...records.map(r => ({
102
+ name: `${r.system_name} ${GRAY(`(${r.status}, ${r.risk_level})`)}`,
103
+ value: r.id,
104
+ })),
105
+ ],
106
+ });
107
+ cmd += ` ${recordChoice}`;
108
+ }
109
+ }
110
+ blank();
111
+ info("Running", GREEN(cmd));
112
+ divider();
113
+ blank();
114
+ const { execSync } = await import("node:child_process");
115
+ try {
116
+ execSync(cmd, { stdio: "inherit" });
117
+ }
118
+ catch {
119
+ process.exit(1);
120
+ }
121
+ })
37
122
  .addCommand(new Command("add")
38
123
  .description("Create a new governance record")
39
124
  .option("-n, --name <name>", "System name")
@@ -119,10 +204,10 @@ export const governanceCommand = new Command("governance")
119
204
  console.error(` Error: Governance record "${id}" not found.`);
120
205
  process.exit(1);
121
206
  }
122
- const approverName = options.approver || await input({ message: "Approver name:", default: "" });
123
- const approverRole = options.role || await input({ message: "Approver role:", default: "" });
124
- const approverEmail = options.email || await input({ message: "Approver email:", default: "" });
125
- const authority = options.authority || await input({ message: "Approval authority:", default: "" });
207
+ const approverName = options.approver || await input({ message: "Approver full name:", default: "" });
208
+ const approverRole = options.role || await input({ message: "Approver role/title (e.g., 'CISO', 'CTO'):", default: "" });
209
+ const approverEmail = options.email || await input({ message: "Approver email (optional):", default: "" });
210
+ const authority = options.authority || await input({ message: "Approval authority (e.g., 'AI Ethics Board', 'Security Committee'):", default: "" });
126
211
  const decision = (options.decision || await select({
127
212
  message: "Decision:",
128
213
  choices: [
@@ -132,9 +217,9 @@ export const governanceCommand = new Command("governance")
132
217
  ],
133
218
  }));
134
219
  const validFrom = options.validFrom || new Date().toISOString().split("T")[0];
135
- const validUntil = options.validUntil || await input({ message: "Valid until (YYYY-MM-DD, or blank for indefinite):", default: "" });
136
- const conditionsStr = options.conditions || await input({ message: "Conditions (comma-separated):", default: "" });
137
- const rationale = options.rationale || await input({ message: "Rationale:", default: "" });
220
+ const validUntil = options.validUntil || await input({ message: "Valid until YYYY-MM-DD (or press Enter for indefinite):", default: "" });
221
+ const conditionsStr = options.conditions || await input({ message: "Conditions (comma-separated, or press Enter to skip):", default: "" });
222
+ const rationale = options.rationale || await input({ message: "Rationale (why was this decision made?):", default: "" });
138
223
  const updated = setGovernanceApproval(root, record.id, {
139
224
  approver_name: approverName,
140
225
  approver_role: approverRole,
@@ -182,7 +267,7 @@ export const governanceCommand = new Command("governance")
182
267
  console.error(` Error: Governance record "${id}" not found.`);
183
268
  process.exit(1);
184
269
  }
185
- const title = options.title || await input({ message: "Evidence title:", default: "" });
270
+ const title = options.title || await input({ message: "Evidence title (e.g., 'DPIA Report Q4 2026'):", default: "" });
186
271
  const sourceSystem = (options.source || await select({
187
272
  message: "Source system:",
188
273
  choices: [
@@ -198,7 +283,7 @@ export const governanceCommand = new Command("governance")
198
283
  { name: "Other", value: "other" },
199
284
  ],
200
285
  }));
201
- const reference = options.reference || await input({ message: "Reference (ticket ID, URL, doc name):", default: "" });
286
+ const reference = options.reference || await input({ message: "Reference (ticket ID, URL, or document path):", default: "" });
202
287
  const evidenceType = await select({
203
288
  message: "Evidence type:",
204
289
  choices: [
@@ -214,7 +299,7 @@ export const governanceCommand = new Command("governance")
214
299
  { name: "Other", value: "other" },
215
300
  ],
216
301
  });
217
- const locationDesc = await input({ message: "Location description:", default: "" });
302
+ const locationDesc = await input({ message: "Location description (where to find it, optional):", default: "" });
218
303
  const evidence = createEvidenceRef({
219
304
  type: evidenceType,
220
305
  title,
@@ -507,12 +592,12 @@ export const governanceCommand = new Command("governance")
507
592
  console.error(` Error: Governance record "${id}" not found.`);
508
593
  process.exit(1);
509
594
  }
510
- const assessor = options.assessor || await input({ message: "Assessor name:", default: "" });
511
- const methodology = options.methodology || await input({ message: "Methodology:", default: "" });
512
- const score = options.score || await input({ message: "Risk score:", default: "" });
513
- const residual = options.residual || await input({ message: "Residual risk level:", default: "" });
514
- const risksStr = await input({ message: "Identified risks (comma-separated):", default: "" });
515
- const mitigationsStr = await input({ message: "Mitigation measures (comma-separated):", default: "" });
595
+ const assessor = options.assessor || await input({ message: "Risk assessor name:", default: "" });
596
+ const methodology = options.methodology || await input({ message: "Methodology (e.g., 'NIST RMF', 'ISO 27005'):", default: "" });
597
+ const score = options.score || await input({ message: "Risk score (e.g., '7.5/10', 'High'):", default: "" });
598
+ const residual = options.residual || await input({ message: "Residual risk level (low/medium/high):", default: "" });
599
+ const risksStr = await input({ message: "Identified risks (comma-separated, or Enter to skip):", default: "" });
600
+ const mitigationsStr = await input({ message: "Mitigation measures (comma-separated, or Enter to skip):", default: "" });
516
601
  const updated = setGovernanceRiskAssessment(root, record.id, {
517
602
  id: `risk-${Date.now()}`,
518
603
  assessor,
@@ -552,11 +637,11 @@ export const governanceCommand = new Command("governance")
552
637
  console.error(` Error: Governance record "${id}" not found.`);
553
638
  process.exit(1);
554
639
  }
555
- const policyId = options.policyId || await input({ message: "Policy ID:", default: "" });
556
- const policyName = options.policyName || await input({ message: "Policy name:", default: "" });
640
+ const policyId = options.policyId || await input({ message: "Policy ID (e.g., 'POL-SEC-001'):", default: "" });
641
+ const policyName = options.policyName || await input({ message: "Policy name (e.g., 'Information Security Policy'):", default: "" });
557
642
  const version = options.pv || await input({ message: "Policy version:", default: "1.0" });
558
- const standard = options.standard || await input({ message: "Standard:", default: "" });
559
- const clausesStr = await input({ message: "Applicable clauses (comma-separated):", default: "" });
643
+ const standard = options.standard || await input({ message: "Standard (e.g., 'GDPR', 'ISO 27001'):", default: "" });
644
+ const clausesStr = await input({ message: "Applicable clauses (comma-separated, or Enter to skip):", default: "" });
560
645
  const updated = setGovernancePolicyBasis(root, record.id, {
561
646
  policy_id: policyId,
562
647
  policy_name: policyName,
@@ -633,11 +718,11 @@ export const governanceCommand = new Command("governance")
633
718
  console.error(` Error: Governance record "${id}" not found.`);
634
719
  process.exit(1);
635
720
  }
636
- const categoriesStr = options.categories || await input({ message: "Personal data categories (comma-separated):", default: "" });
637
- const purposesStr = options.purposes || await input({ message: "Processing purposes (comma-separated):", default: "" });
638
- const subjectsStr = await input({ message: "Data subjects (comma-separated):", default: "" });
639
- const transfersStr = await input({ message: "Cross-border transfers (comma-separated):", default: "" });
640
- const retention = options.retention || await input({ message: "Retention period:", default: "" });
721
+ const categoriesStr = options.categories || await input({ message: "Personal data categories (e.g., 'names,emails,IP addresses'):", default: "" });
722
+ const purposesStr = options.purposes || await input({ message: "Processing purposes (e.g., 'user auth,analytics'):", default: "" });
723
+ const subjectsStr = await input({ message: "Data subjects (e.g., 'customers,employees', or Enter to skip):", default: "" });
724
+ const transfersStr = await input({ message: "Cross-border transfers (e.g., 'US,EU', or Enter to skip):", default: "" });
725
+ const retention = options.retention || await input({ message: "Retention period (e.g., '2 years', '90 days'):", default: "" });
641
726
  const updated = setGovernanceDataInventory(root, record.id, {
642
727
  personal_data_categories: categoriesStr ? categoriesStr.split(",").map((s) => s.trim()).filter(Boolean) : [],
643
728
  processing_purposes: purposesStr ? purposesStr.split(",").map((s) => s.trim()).filter(Boolean) : [],
@@ -669,11 +754,11 @@ export const governanceCommand = new Command("governance")
669
754
  console.error(` Error: Governance record "${id}" not found.`);
670
755
  process.exit(1);
671
756
  }
672
- const committeeName = options.committee || await input({ message: "Committee name:", default: "" });
673
- const meetingRef = options.meetingRef || await input({ message: "Meeting reference:", default: "" });
757
+ const committeeName = options.committee || await input({ message: "Committee name (e.g., 'AI Ethics Board'):", default: "" });
758
+ const meetingRef = options.meetingRef || await input({ message: "Meeting reference (e.g., 'MIN-2026-001'):", default: "" });
674
759
  const meetingDate = options.meetingDate || await input({ message: "Meeting date (YYYY-MM-DD):", default: "" });
675
- const attendeesStr = await input({ message: "Attendees (comma-separated):", default: "" });
676
- const summary = await input({ message: "Decision summary:", default: "" });
760
+ const attendeesStr = await input({ message: "Attendees (comma-separated names, or Enter to skip):", default: "" });
761
+ const summary = await input({ message: "Decision summary (what was decided):", default: "" });
677
762
  const updated = setGovernanceCommittee(root, record.id, {
678
763
  committee_name: committeeName,
679
764
  meeting_date: meetingDate,
@@ -707,9 +792,9 @@ export const governanceCommand = new Command("governance")
707
792
  console.error(` Error: Governance record "${id}" not found.`);
708
793
  process.exit(1);
709
794
  }
710
- const frameworksStr = options.frameworks || await input({ message: "Frameworks (comma-separated):", default: "" });
711
- const controlsStr = options.controls || await input({ message: "Controls satisfied (comma-separated):", default: "" });
712
- const packsStr = await input({ message: "Control pack IDs (comma-separated):", default: "" });
795
+ const frameworksStr = options.frameworks || await input({ message: "Frameworks (e.g., 'GDPR,OWASP'):", default: "" });
796
+ const controlsStr = options.controls || await input({ message: "Controls satisfied (e.g., 'GDPR-ART32-002', or Enter to skip):", default: "" });
797
+ const packsStr = await input({ message: "Control pack IDs (comma-separated, or Enter to skip):", default: "" });
713
798
  const updated = setGovernanceComplianceLinks(root, record.id, {
714
799
  frameworks: frameworksStr ? frameworksStr.split(",").map((s) => s.trim()).filter(Boolean) : [],
715
800
  controls_satisfied: controlsStr ? controlsStr.split(",").map((s) => s.trim()).filter(Boolean) : [],
@@ -2,8 +2,52 @@ import { Command } from "commander";
2
2
  import { ensureGESInitialized } from "../utils/project.js";
3
3
  import { installHooks, uninstallHooks } from "@greenarmor/ges-git-hooks";
4
4
  import { recordActivity } from "@greenarmor/ges-core";
5
+ import { banner, blank, DIM, YELLOW } from "../utils/ui.js";
6
+ import { select } from "../utils/prompts.js";
7
+ import * as fs from "node:fs";
8
+ import * as path from "node:path";
5
9
  export const hooksCommand = new Command("hooks")
6
10
  .description("Manage GESF git hooks (pre-commit compliance enforcement)")
11
+ .action(async () => {
12
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
13
+ hooksCommand.outputHelp();
14
+ return;
15
+ }
16
+ banner("Git Hooks", "Pre-commit compliance enforcement");
17
+ let root;
18
+ try {
19
+ root = ensureGESInitialized();
20
+ }
21
+ catch {
22
+ const { error } = await import("../utils/ui.js");
23
+ error("GESF is not initialized.", "Run `ges init` first.");
24
+ blank();
25
+ return;
26
+ }
27
+ const hookPath = path.join(root, ".git", "hooks", "pre-commit");
28
+ const isInstalled = fs.existsSync(hookPath);
29
+ const action = await select({
30
+ message: "What would you like to do?",
31
+ choices: [
32
+ ...(isInstalled
33
+ ? [{ name: `Uninstall pre-commit hook ${DIM("— remove compliance gate")}`, value: "uninstall" }]
34
+ : [{ name: `Install pre-commit hook ${DIM("— blocks commits with critical findings")}`, value: "install" }]),
35
+ { name: `${YELLOW("Exit")} ${DIM("— return to terminal")}`, value: "exit" },
36
+ ],
37
+ });
38
+ if (action === "exit") {
39
+ blank();
40
+ return;
41
+ }
42
+ blank();
43
+ const { execSync } = await import("node:child_process");
44
+ try {
45
+ execSync(`ges hooks ${action}`, { stdio: "inherit" });
46
+ }
47
+ catch {
48
+ process.exit(1);
49
+ }
50
+ })
7
51
  .addCommand(new Command("install")
8
52
  .description("Install the pre-commit hook that runs ges audit before each commit")
9
53
  .action(async () => {
@@ -2,8 +2,37 @@ import { Command } from "commander";
2
2
  import * as readline from "node:readline";
3
3
  import { handleRequest } from "@greenarmor/ges-mcp-server";
4
4
  import { mcpSetupCommand } from "./mcp-setup.js";
5
+ import { banner, blank, DIM, YELLOW } from "../utils/ui.js";
6
+ import { select } from "../utils/prompts.js";
5
7
  export const mcpCommand = new Command("mcp")
6
8
  .description("MCP AI Compliance Assistant")
9
+ .action(async () => {
10
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
11
+ mcpCommand.outputHelp();
12
+ return;
13
+ }
14
+ banner("GESF MCP Server", "AI Compliance Assistant Integration");
15
+ const action = await select({
16
+ message: "What would you like to do?",
17
+ choices: [
18
+ { name: `Setup MCP clients ${DIM("— configure Claude, Cursor, VS Code, etc.")}`, value: "setup" },
19
+ { name: `Start MCP server ${DIM("— JSON-RPC over stdio (for advanced use)")}`, value: "start" },
20
+ { name: `${YELLOW("Exit")} ${DIM("— return to terminal")}`, value: "exit" },
21
+ ],
22
+ });
23
+ if (action === "exit") {
24
+ blank();
25
+ return;
26
+ }
27
+ blank();
28
+ const { execSync } = await import("node:child_process");
29
+ try {
30
+ execSync(`ges mcp ${action}`, { stdio: "inherit" });
31
+ }
32
+ catch {
33
+ process.exit(1);
34
+ }
35
+ })
7
36
  .addCommand(new Command("start")
8
37
  .description("Start the GESF MCP server (JSON-RPC over stdio)")
9
38
  .action(() => {
@@ -3,11 +3,92 @@ import { getAllPacks, listPackIds } from "@greenarmor/ges-policy-engine";
3
3
  import { ensureGESInitialized, writeFileSync } from "../utils/project.js";
4
4
  import { addFrameworkToConfig, removeFrameworkFromConfig, recordActivity } from "@greenarmor/ges-core";
5
5
  import { showNextStepsMenu } from "../utils/next-steps.js";
6
- import { banner, blank, success, error, BOLD, CYAN, DIM, GRAY } from "../utils/ui.js";
6
+ import { banner, blank, success, error, BOLD, CYAN, DIM, GRAY, YELLOW } from "../utils/ui.js";
7
+ import { select } from "../utils/prompts.js";
7
8
  import * as fs from "node:fs";
8
9
  import * as path from "node:path";
9
10
  const policyCmd = new Command("policy")
10
- .description("Manage policy packs");
11
+ .description("Manage policy packs")
12
+ .action(async () => {
13
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
14
+ policyCmd.outputHelp();
15
+ return;
16
+ }
17
+ banner("Policy Packs", "Compliance control management");
18
+ let root;
19
+ try {
20
+ root = ensureGESInitialized();
21
+ }
22
+ catch {
23
+ error("GESF is not initialized.", "Run `ges init` first.");
24
+ blank();
25
+ return;
26
+ }
27
+ const installedPacks = fs.existsSync(path.join(root, "controls"))
28
+ ? fs.readdirSync(path.join(root, "controls")).filter(d => {
29
+ try {
30
+ return fs.statSync(path.join(root, "controls", d)).isDirectory();
31
+ }
32
+ catch {
33
+ return false;
34
+ }
35
+ })
36
+ : [];
37
+ if (installedPacks.length > 0) {
38
+ console.log(` ${BOLD("Installed Packs")} ${GRAY(`(${installedPacks.length})`)}`);
39
+ installedPacks.forEach(p => console.log(` ${GRAY("•")} ${p}`));
40
+ console.log("");
41
+ }
42
+ const action = await select({
43
+ message: "What would you like to do?",
44
+ choices: [
45
+ { name: `List all available packs ${DIM("— see what can be installed")}`, value: "list" },
46
+ { name: `Install a pack ${DIM("— add compliance controls")}`, value: "install" },
47
+ ...(installedPacks.length > 0 ? [
48
+ { name: `Remove a pack ${DIM(`(${installedPacks.length} installed)`)}`, value: "remove" },
49
+ ] : []),
50
+ { name: `${YELLOW("Exit")} ${DIM("— return to terminal")}`, value: "exit" },
51
+ ],
52
+ });
53
+ if (action === "exit") {
54
+ blank();
55
+ return;
56
+ }
57
+ let cmd = "ges policy";
58
+ if (action === "list") {
59
+ cmd += " list";
60
+ }
61
+ else if (action === "install") {
62
+ const packs = getAllPacks();
63
+ const packChoice = await select({
64
+ message: "Select a pack to install:",
65
+ choices: [
66
+ ...packs.map(p => ({
67
+ name: `${p.id.padEnd(16)} ${DIM(p.name)} ${GRAY(`(${p.controls.length} controls)`)}`,
68
+ value: p.id,
69
+ })),
70
+ ],
71
+ });
72
+ cmd += ` install ${packChoice}`;
73
+ }
74
+ else if (action === "remove") {
75
+ const packChoice = await select({
76
+ message: "Select a pack to remove:",
77
+ choices: [
78
+ ...installedPacks.map(p => ({ name: p, value: p })),
79
+ ],
80
+ });
81
+ cmd += ` remove ${packChoice}`;
82
+ }
83
+ blank();
84
+ const { execSync } = await import("node:child_process");
85
+ try {
86
+ execSync(cmd, { stdio: "inherit" });
87
+ }
88
+ catch {
89
+ process.exit(1);
90
+ }
91
+ });
11
92
  policyCmd
12
93
  .command("list")
13
94
  .description("List available policy packs")
package/package.json CHANGED
@@ -3,19 +3,19 @@
3
3
  "ges": "./dist/cli.js"
4
4
  },
5
5
  "dependencies": {
6
- "@greenarmor/ges-audit-engine": "1.5.2",
7
- "@greenarmor/ges-cicd-generator": "1.5.2",
8
- "@greenarmor/ges-compliance-engine": "1.5.2",
9
- "@greenarmor/ges-core": "1.5.2",
10
- "@greenarmor/ges-doc-generator": "1.5.2",
11
- "@greenarmor/ges-git-hooks": "1.5.2",
12
- "@greenarmor/ges-mcp-server": "1.5.2",
13
- "@greenarmor/ges-policy-engine": "1.5.2",
14
- "@greenarmor/ges-report-generator": "1.5.2",
15
- "@greenarmor/ges-rules-engine": "1.5.2",
16
- "@greenarmor/ges-scanner-integration": "1.5.2",
17
- "@greenarmor/ges-scoring-engine": "1.5.2",
18
- "@greenarmor/ges-web-dashboard": "1.5.2",
6
+ "@greenarmor/ges-audit-engine": "1.5.3",
7
+ "@greenarmor/ges-cicd-generator": "1.5.3",
8
+ "@greenarmor/ges-compliance-engine": "1.5.3",
9
+ "@greenarmor/ges-core": "1.5.3",
10
+ "@greenarmor/ges-doc-generator": "1.5.3",
11
+ "@greenarmor/ges-git-hooks": "1.5.3",
12
+ "@greenarmor/ges-mcp-server": "1.5.3",
13
+ "@greenarmor/ges-policy-engine": "1.5.3",
14
+ "@greenarmor/ges-report-generator": "1.5.3",
15
+ "@greenarmor/ges-rules-engine": "1.5.3",
16
+ "@greenarmor/ges-scanner-integration": "1.5.3",
17
+ "@greenarmor/ges-scoring-engine": "1.5.3",
18
+ "@greenarmor/ges-web-dashboard": "1.5.3",
19
19
  "chalk": "^5.6.2",
20
20
  "commander": "^13.0.0"
21
21
  },
@@ -60,7 +60,7 @@
60
60
  },
61
61
  "type": "module",
62
62
  "types": "./dist/index.d.ts",
63
- "version": "1.5.2",
63
+ "version": "1.5.3",
64
64
  "scripts": {
65
65
  "build": "tsc",
66
66
  "clean": "rm -rf dist tsconfig.tsbuildinfo",