@aigrc/cli 0.1.0 → 0.2.0

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/aigrc.js CHANGED
@@ -1,4 +1,10 @@
1
1
  #!/usr/bin/env node
2
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
3
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
4
+ }) : x)(function(x) {
5
+ if (typeof require !== "undefined") return require.apply(this, arguments);
6
+ throw Error('Dynamic require of "' + x + '" is not supported');
7
+ });
2
8
 
3
9
  // src/bin/aigrc.ts
4
10
  import { program } from "commander";
@@ -714,59 +720,414 @@ function sanitizeFileName2(name) {
714
720
 
715
721
  // src/commands/validate.ts
716
722
  import { Command as Command4 } from "commander";
717
- import chalk5 from "chalk";
723
+ import chalk6 from "chalk";
718
724
  import ora3 from "ora";
719
- import path4 from "path";
725
+ import path5 from "path";
720
726
  import fs3 from "fs/promises";
727
+ import YAML from "yaml";
721
728
  import {
722
729
  loadAssetCard,
723
730
  classifyRisk,
724
731
  validateAssetCard
725
732
  } from "@aigrc/core";
733
+
734
+ // src/utils/exit-codes.ts
735
+ function exit(code) {
736
+ process.exit(code);
737
+ }
738
+
739
+ // src/formatters/sarif.ts
740
+ function formatSarif(results, version = "0.1.0") {
741
+ const sarifResults = [];
742
+ const artifacts = [];
743
+ const seenPaths = /* @__PURE__ */ new Set();
744
+ for (const result of results) {
745
+ if (!seenPaths.has(result.path)) {
746
+ seenPaths.add(result.path);
747
+ artifacts.push({
748
+ location: {
749
+ uri: result.path
750
+ },
751
+ mimeType: "application/x-yaml"
752
+ });
753
+ }
754
+ if (!result.validation.valid) {
755
+ for (const error of result.validation.errors) {
756
+ sarifResults.push({
757
+ ruleId: "AIGRC001",
758
+ level: "error",
759
+ message: {
760
+ text: error
761
+ },
762
+ locations: [
763
+ {
764
+ physicalLocation: {
765
+ artifactLocation: {
766
+ uri: result.path
767
+ }
768
+ }
769
+ }
770
+ ],
771
+ properties: {
772
+ cardId: result.card?.id,
773
+ cardName: result.card?.name
774
+ }
775
+ });
776
+ }
777
+ } else {
778
+ sarifResults.push({
779
+ ruleId: "AIGRC001",
780
+ level: "none",
781
+ message: {
782
+ text: "Asset card validation passed"
783
+ },
784
+ locations: [
785
+ {
786
+ physicalLocation: {
787
+ artifactLocation: {
788
+ uri: result.path
789
+ }
790
+ }
791
+ }
792
+ ],
793
+ properties: {
794
+ cardId: result.card?.id,
795
+ cardName: result.card?.name,
796
+ riskLevel: result.card?.classification?.riskLevel
797
+ }
798
+ });
799
+ }
800
+ }
801
+ const sarif = {
802
+ version: "2.1.0",
803
+ $schema: "https://raw.githubusercontent.com/oasis-tcs/sarif-spec/master/Schemata/sarif-schema-2.1.0.json",
804
+ runs: [
805
+ {
806
+ tool: {
807
+ driver: {
808
+ name: "AIGRC",
809
+ version,
810
+ informationUri: "https://github.com/aigrc/aigrc",
811
+ rules: [
812
+ {
813
+ id: "AIGRC001",
814
+ name: "AssetCardValidation",
815
+ shortDescription: {
816
+ text: "Asset card must be valid according to AIGRC schema"
817
+ },
818
+ fullDescription: {
819
+ text: "Validates asset cards against AIGRC compliance requirements including risk classification, ownership, and regulatory framework mappings."
820
+ },
821
+ help: {
822
+ text: "Ensure your asset card includes all required fields and follows the AIGRC schema. Run 'aigrc validate --help' for more information."
823
+ },
824
+ defaultConfiguration: {
825
+ level: "error"
826
+ }
827
+ }
828
+ ]
829
+ }
830
+ },
831
+ results: sarifResults,
832
+ artifacts
833
+ }
834
+ ]
835
+ };
836
+ return sarif;
837
+ }
838
+ function sarifToJson(sarif, pretty = true) {
839
+ return JSON.stringify(sarif, null, pretty ? 2 : 0);
840
+ }
841
+
842
+ // src/formatters/text.ts
843
+ import chalk5 from "chalk";
844
+ import path4 from "path";
845
+ function printValidationSummary(results) {
846
+ console.log(chalk5.bold("Validation Summary"));
847
+ console.log(chalk5.dim("\u2500".repeat(50)));
848
+ console.log();
849
+ for (const result of results) {
850
+ const fileName = path4.basename(result.path);
851
+ if (!result.validation.valid) {
852
+ console.log(chalk5.red(`\u2717 ${fileName}`));
853
+ for (const error of result.validation.errors) {
854
+ console.log(chalk5.red(` Error: ${error}`));
855
+ }
856
+ if (result.fixed && result.fixedFields && result.fixedFields.length > 0) {
857
+ console.log(chalk5.yellow(` Fixed: ${result.fixedFields.join(", ")}`));
858
+ }
859
+ } else {
860
+ console.log(chalk5.green(`\u2713 ${fileName}`));
861
+ if (result.fixed && result.fixedFields && result.fixedFields.length > 0) {
862
+ console.log(chalk5.yellow(` Fixed: ${result.fixedFields.join(", ")}`));
863
+ }
864
+ if (result.card && result.classification) {
865
+ const tierColor = getRiskLevelColor(result.classification.riskLevel);
866
+ console.log(
867
+ chalk5.dim(" Risk Level: ") + tierColor(result.classification.riskLevel)
868
+ );
869
+ if (result.classification.euAiActCategory) {
870
+ console.log(
871
+ chalk5.dim(" EU AI Act: ") + chalk5.yellow(result.classification.euAiActCategory)
872
+ );
873
+ }
874
+ }
875
+ }
876
+ console.log();
877
+ }
878
+ const valid = results.filter((r) => r.validation.valid).length;
879
+ const invalid = results.filter((r) => !r.validation.valid).length;
880
+ const fixed = results.filter((r) => r.fixed).length;
881
+ console.log(chalk5.dim("\u2500".repeat(50)));
882
+ console.log(
883
+ `Total: ${results.length} | ` + chalk5.green(`Valid: ${valid}`) + ` | ` + chalk5.red(`Invalid: ${invalid}`) + (fixed > 0 ? ` | ${chalk5.yellow(`Fixed: ${fixed}`)}` : "")
884
+ );
885
+ }
886
+ function getRiskLevelColor(level) {
887
+ switch (level) {
888
+ case "minimal":
889
+ return chalk5.green;
890
+ case "limited":
891
+ return chalk5.yellow;
892
+ case "high":
893
+ return chalk5.red;
894
+ case "unacceptable":
895
+ return chalk5.magenta;
896
+ default:
897
+ return chalk5.white;
898
+ }
899
+ }
900
+
901
+ // src/fixers/auto-fix.ts
902
+ function autoFixAssetCard(card) {
903
+ const fixedFields = [];
904
+ const fixedCard = JSON.parse(JSON.stringify(card));
905
+ if (!fixedCard.metadata?.createdAt) {
906
+ if (!fixedCard.metadata) {
907
+ fixedCard.metadata = {
908
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
909
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
910
+ version: "1.0.0"
911
+ };
912
+ } else {
913
+ fixedCard.metadata.createdAt = (/* @__PURE__ */ new Date()).toISOString();
914
+ }
915
+ fixedFields.push("metadata.createdAt");
916
+ } else if (!isValidISODate(fixedCard.metadata.createdAt)) {
917
+ fixedCard.metadata.createdAt = normalizeDate(fixedCard.metadata.createdAt);
918
+ fixedFields.push("metadata.createdAt (format)");
919
+ }
920
+ if (!fixedCard.metadata?.updatedAt) {
921
+ if (!fixedCard.metadata) {
922
+ fixedCard.metadata = {
923
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
924
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
925
+ version: "1.0.0"
926
+ };
927
+ } else {
928
+ fixedCard.metadata.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
929
+ }
930
+ fixedFields.push("metadata.updatedAt");
931
+ } else if (!isValidISODate(fixedCard.metadata.updatedAt)) {
932
+ fixedCard.metadata.updatedAt = normalizeDate(fixedCard.metadata.updatedAt);
933
+ fixedFields.push("metadata.updatedAt (format)");
934
+ }
935
+ if (!fixedCard.metadata?.version) {
936
+ if (!fixedCard.metadata) {
937
+ fixedCard.metadata = {
938
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
939
+ updatedAt: (/* @__PURE__ */ new Date()).toISOString(),
940
+ version: "1.0.0"
941
+ };
942
+ } else {
943
+ fixedCard.metadata.version = "1.0.0";
944
+ }
945
+ fixedFields.push("metadata.version");
946
+ }
947
+ if (fixedCard.classification?.riskLevel) {
948
+ const normalized = normalizeRiskLevel(fixedCard.classification.riskLevel);
949
+ if (normalized !== fixedCard.classification.riskLevel) {
950
+ fixedCard.classification.riskLevel = normalized;
951
+ fixedFields.push("classification.riskLevel");
952
+ }
953
+ }
954
+ if (fixedCard.classification?.riskFactors?.piiProcessing !== void 0) {
955
+ const pii = fixedCard.classification.riskFactors.piiProcessing;
956
+ if (typeof pii === "boolean") {
957
+ fixedCard.classification.riskFactors.piiProcessing = pii ? "yes" : "no";
958
+ fixedFields.push("classification.riskFactors.piiProcessing");
959
+ }
960
+ }
961
+ if (!fixedCard.id) {
962
+ fixedCard.id = generateId(fixedCard.name);
963
+ fixedFields.push("id");
964
+ }
965
+ if (!fixedCard.name) {
966
+ fixedCard.name = "Unnamed Asset";
967
+ fixedFields.push("name");
968
+ }
969
+ if (!fixedCard.description) {
970
+ fixedCard.description = "No description provided";
971
+ fixedFields.push("description");
972
+ }
973
+ if (!fixedCard.classification) {
974
+ fixedCard.classification = {
975
+ riskLevel: "minimal",
976
+ riskFactors: {
977
+ autonomousDecisions: false,
978
+ customerFacing: false,
979
+ toolExecution: false,
980
+ externalDataAccess: false,
981
+ piiProcessing: "unknown",
982
+ highStakesDecisions: false
983
+ }
984
+ };
985
+ fixedFields.push("classification");
986
+ }
987
+ if (!fixedCard.classification.riskFactors) {
988
+ fixedCard.classification.riskFactors = {
989
+ autonomousDecisions: false,
990
+ customerFacing: false,
991
+ toolExecution: false,
992
+ externalDataAccess: false,
993
+ piiProcessing: "unknown",
994
+ highStakesDecisions: false
995
+ };
996
+ fixedFields.push("classification.riskFactors");
997
+ }
998
+ return {
999
+ fixed: fixedFields.length > 0,
1000
+ fixedFields,
1001
+ card: fixedCard
1002
+ };
1003
+ }
1004
+ function isValidISODate(dateStr) {
1005
+ const iso8601Regex = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?$/;
1006
+ if (!iso8601Regex.test(dateStr)) {
1007
+ return false;
1008
+ }
1009
+ const date = new Date(dateStr);
1010
+ return !isNaN(date.getTime());
1011
+ }
1012
+ function normalizeDate(dateStr) {
1013
+ const date = new Date(dateStr);
1014
+ if (isNaN(date.getTime())) {
1015
+ return (/* @__PURE__ */ new Date()).toISOString();
1016
+ }
1017
+ return date.toISOString();
1018
+ }
1019
+ function normalizeRiskLevel(level) {
1020
+ const normalized = level.toLowerCase().trim();
1021
+ const validLevels = ["minimal", "limited", "high", "unacceptable"];
1022
+ if (validLevels.includes(normalized)) {
1023
+ return normalized;
1024
+ }
1025
+ const mappings = {
1026
+ low: "minimal",
1027
+ medium: "limited",
1028
+ critical: "unacceptable",
1029
+ extreme: "unacceptable",
1030
+ none: "minimal"
1031
+ };
1032
+ return mappings[normalized] || "minimal";
1033
+ }
1034
+ function generateId(name) {
1035
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "").substring(0, 50);
1036
+ }
1037
+
1038
+ // src/commands/validate.ts
726
1039
  var DEFAULT_CARDS_DIR3 = ".aigrc/cards";
727
- var validateCommand = new Command4("validate").description("Validate asset cards against compliance requirements").argument("[path]", "Path to asset card or cards directory").option("-s, --strict", "Fail on warnings as well as errors").option("-o, --output <format>", "Output format (text, json)", "text").option("-a, --all", "Validate all cards in the cards directory").action(async (cardPath, options) => {
1040
+ var validateCommand = new Command4("validate").description("Validate asset cards against compliance requirements").argument("[path]", "Path to asset card or cards directory").option("-s, --strict", "Fail on warnings as well as errors").option("-o, --output <format>", "Output format (text, json, sarif)", "text").option("-a, --all", "Validate all cards in the cards directory").option("--fix", "Automatically fix common issues").option("--dry-run", "Preview fixes without saving (requires --fix)").option("--output-file <path>", "Write output to file instead of stdout").action(async (cardPath, options) => {
728
1041
  await runValidate(cardPath, options);
729
1042
  });
730
1043
  async function runValidate(cardPath, options) {
731
- if (options.output === "text") {
1044
+ if (options.dryRun && !options.fix) {
1045
+ if (options.output === "text") {
1046
+ console.error(chalk6.red("Error: --dry-run requires --fix"));
1047
+ } else {
1048
+ console.error(JSON.stringify({ error: "--dry-run requires --fix" }));
1049
+ }
1050
+ exit(2 /* INVALID_ARGUMENTS */);
1051
+ }
1052
+ if (options.output === "text" && !options.outputFile) {
732
1053
  printHeader();
733
1054
  }
734
1055
  const cardsToValidate = [];
735
1056
  if (options.all || !cardPath) {
736
- const cardsDir = path4.join(process.cwd(), DEFAULT_CARDS_DIR3);
1057
+ const cardsDir = path5.join(process.cwd(), DEFAULT_CARDS_DIR3);
737
1058
  try {
738
1059
  const files = await fs3.readdir(cardsDir);
739
1060
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
740
1061
  for (const file of yamlFiles) {
741
- cardsToValidate.push(path4.join(cardsDir, file));
1062
+ cardsToValidate.push(path5.join(cardsDir, file));
742
1063
  }
743
- } catch {
744
- if (options.output === "text") {
745
- console.log(chalk5.yellow("No cards directory found."));
746
- console.log(chalk5.dim(`Expected: ${cardsDir}`));
747
- console.log(chalk5.dim("Run `aigrc init` to initialize AIGRC."));
1064
+ } catch (error) {
1065
+ if (options.output === "text" && !options.outputFile) {
1066
+ console.log(chalk6.yellow("No cards directory found."));
1067
+ console.log(chalk6.dim(`Expected: ${cardsDir}`));
1068
+ console.log(chalk6.dim("Run `aigrc init` to initialize AIGRC."));
748
1069
  } else {
749
- console.log(JSON.stringify({ error: "No cards directory found" }));
1070
+ const output = JSON.stringify({ error: "No cards directory found" });
1071
+ if (options.outputFile) {
1072
+ await fs3.writeFile(options.outputFile, output);
1073
+ } else {
1074
+ console.log(output);
1075
+ }
750
1076
  }
751
- process.exit(1);
1077
+ exit(4 /* FILE_NOT_FOUND */);
752
1078
  }
753
1079
  } else {
754
- cardsToValidate.push(path4.resolve(process.cwd(), cardPath));
1080
+ const resolvedPath = path5.resolve(process.cwd(), cardPath);
1081
+ try {
1082
+ await fs3.access(resolvedPath);
1083
+ cardsToValidate.push(resolvedPath);
1084
+ } catch {
1085
+ if (options.output === "text" && !options.outputFile) {
1086
+ console.log(chalk6.red(`Error: File not found: ${cardPath}`));
1087
+ } else {
1088
+ const output = JSON.stringify({ error: `File not found: ${cardPath}` });
1089
+ if (options.outputFile) {
1090
+ await fs3.writeFile(options.outputFile, output);
1091
+ } else {
1092
+ console.log(output);
1093
+ }
1094
+ }
1095
+ exit(4 /* FILE_NOT_FOUND */);
1096
+ }
755
1097
  }
756
1098
  if (cardsToValidate.length === 0) {
757
- if (options.output === "text") {
758
- console.log(chalk5.yellow("No asset cards found to validate."));
1099
+ if (options.output === "text" && !options.outputFile) {
1100
+ console.log(chalk6.yellow("No asset cards found to validate."));
759
1101
  } else {
760
- console.log(JSON.stringify({ error: "No asset cards found" }));
1102
+ const output = JSON.stringify({ error: "No asset cards found" });
1103
+ if (options.outputFile) {
1104
+ await fs3.writeFile(options.outputFile, output);
1105
+ } else {
1106
+ console.log(output);
1107
+ }
761
1108
  }
762
- process.exit(1);
1109
+ exit(4 /* FILE_NOT_FOUND */);
763
1110
  }
764
1111
  const results = [];
765
1112
  let hasErrors = false;
766
1113
  for (const cardFile of cardsToValidate) {
767
- const spinner = options.output === "text" ? ora3(`Validating ${path4.basename(cardFile)}...`).start() : void 0;
1114
+ const spinner = options.output === "text" && !options.outputFile ? ora3(`Validating ${path5.basename(cardFile)}...`).start() : void 0;
768
1115
  try {
769
- const card = loadAssetCard(cardFile);
1116
+ let card = loadAssetCard(cardFile);
1117
+ let fixed = false;
1118
+ let fixedFields = [];
1119
+ if (options.fix) {
1120
+ const fixResult = autoFixAssetCard(card);
1121
+ if (fixResult.fixed) {
1122
+ fixed = true;
1123
+ fixedFields = fixResult.fixedFields;
1124
+ card = fixResult.card;
1125
+ if (!options.dryRun) {
1126
+ const yamlContent = YAML.stringify(card);
1127
+ await fs3.writeFile(cardFile, yamlContent, "utf-8");
1128
+ }
1129
+ }
1130
+ }
770
1131
  const validation = validateAssetCard(card);
771
1132
  const classification = classifyRisk(card.classification.riskFactors);
772
1133
  results.push({
@@ -776,13 +1137,17 @@ async function runValidate(cardPath, options) {
776
1137
  valid: validation.valid,
777
1138
  errors: validation.errors ?? []
778
1139
  },
779
- classification
1140
+ classification,
1141
+ fixed,
1142
+ fixedFields
780
1143
  });
781
1144
  if (!validation.valid) {
782
1145
  hasErrors = true;
783
- spinner?.fail(`${path4.basename(cardFile)}: Invalid`);
1146
+ spinner?.fail(`${path5.basename(cardFile)}: Invalid`);
1147
+ } else if (fixed) {
1148
+ spinner?.succeed(`${path5.basename(cardFile)}: Valid (fixed ${fixedFields.length} issues)`);
784
1149
  } else {
785
- spinner?.succeed(`${path4.basename(cardFile)}: Valid`);
1150
+ spinner?.succeed(`${path5.basename(cardFile)}: Valid`);
786
1151
  }
787
1152
  } catch (error) {
788
1153
  hasErrors = true;
@@ -794,76 +1159,93 @@ async function runValidate(cardPath, options) {
794
1159
  errors: [errorMessage]
795
1160
  }
796
1161
  });
797
- spinner?.fail(`${path4.basename(cardFile)}: Parse error`);
1162
+ spinner?.fail(`${path5.basename(cardFile)}: Parse error`);
798
1163
  }
799
1164
  }
800
- if (options.output === "json") {
801
- console.log(JSON.stringify({ results }, null, 2));
802
- } else {
803
- console.log();
804
- printValidationSummary(results);
805
- }
1165
+ await outputResults(results, options);
806
1166
  if (hasErrors) {
807
- process.exit(1);
1167
+ exit(3 /* VALIDATION_ERRORS */);
808
1168
  }
1169
+ exit(0 /* SUCCESS */);
809
1170
  }
810
- function printValidationSummary(results) {
811
- console.log(chalk5.bold("Validation Summary"));
812
- console.log(chalk5.dim("\u2500".repeat(50)));
813
- console.log();
1171
+ async function outputResults(results, options) {
1172
+ let output;
1173
+ switch (options.output) {
1174
+ case "sarif": {
1175
+ const sarif = formatSarif(results);
1176
+ output = sarifToJson(sarif);
1177
+ break;
1178
+ }
1179
+ case "json": {
1180
+ output = JSON.stringify({ results }, null, 2);
1181
+ break;
1182
+ }
1183
+ case "text":
1184
+ default: {
1185
+ if (options.outputFile) {
1186
+ output = formatTextOutput(results);
1187
+ } else {
1188
+ console.log();
1189
+ printValidationSummary(results);
1190
+ return;
1191
+ }
1192
+ }
1193
+ }
1194
+ if (options.outputFile) {
1195
+ await fs3.writeFile(options.outputFile, output, "utf-8");
1196
+ if (options.output === "text") {
1197
+ console.log(chalk6.green(`\u2713 Output written to ${options.outputFile}`));
1198
+ }
1199
+ } else {
1200
+ console.log(output);
1201
+ }
1202
+ }
1203
+ function formatTextOutput(results) {
1204
+ const lines = [];
1205
+ lines.push("Validation Summary");
1206
+ lines.push("\u2500".repeat(50));
1207
+ lines.push("");
814
1208
  for (const result of results) {
815
- const fileName = path4.basename(result.path);
1209
+ const fileName = path5.basename(result.path);
816
1210
  if (!result.validation.valid) {
817
- console.log(chalk5.red(`\u2717 ${fileName}`));
1211
+ lines.push(`\u2717 ${fileName}`);
818
1212
  for (const error of result.validation.errors) {
819
- console.log(chalk5.red(` Error: ${error}`));
1213
+ lines.push(` Error: ${error}`);
820
1214
  }
821
1215
  } else {
822
- console.log(chalk5.green(`\u2713 ${fileName}`));
1216
+ lines.push(`\u2713 ${fileName}`);
1217
+ if (result.fixed && result.fixedFields && result.fixedFields.length > 0) {
1218
+ lines.push(` Fixed: ${result.fixedFields.join(", ")}`);
1219
+ }
823
1220
  if (result.card && result.classification) {
824
- const tierColor = getRiskLevelColor(result.classification.riskLevel);
825
- console.log(
826
- chalk5.dim(" Risk Level: ") + tierColor(result.classification.riskLevel)
827
- );
1221
+ lines.push(` Risk Level: ${result.classification.riskLevel}`);
828
1222
  if (result.classification.euAiActCategory) {
829
- console.log(
830
- chalk5.dim(" EU AI Act: ") + chalk5.yellow(result.classification.euAiActCategory)
831
- );
1223
+ lines.push(` EU AI Act: ${result.classification.euAiActCategory}`);
832
1224
  }
833
1225
  }
834
1226
  }
835
- console.log();
1227
+ lines.push("");
836
1228
  }
837
1229
  const valid = results.filter((r) => r.validation.valid).length;
838
1230
  const invalid = results.filter((r) => !r.validation.valid).length;
839
- console.log(chalk5.dim("\u2500".repeat(50)));
840
- console.log(
841
- `Total: ${results.length} | ` + chalk5.green(`Valid: ${valid}`) + ` | ` + chalk5.red(`Invalid: ${invalid}`)
1231
+ const fixed = results.filter((r) => r.fixed).length;
1232
+ lines.push("\u2500".repeat(50));
1233
+ lines.push(
1234
+ `Total: ${results.length} | Valid: ${valid} | Invalid: ${invalid}` + (fixed > 0 ? ` | Fixed: ${fixed}` : "")
842
1235
  );
843
- }
844
- function getRiskLevelColor(level) {
845
- switch (level) {
846
- case "minimal":
847
- return chalk5.green;
848
- case "limited":
849
- return chalk5.yellow;
850
- case "high":
851
- return chalk5.red;
852
- case "unacceptable":
853
- return chalk5.magenta;
854
- default:
855
- return chalk5.white;
856
- }
1236
+ return lines.join("\n");
857
1237
  }
858
1238
 
859
1239
  // src/commands/status.ts
860
1240
  import { Command as Command5 } from "commander";
861
- import chalk6 from "chalk";
862
- import path5 from "path";
1241
+ import chalk7 from "chalk";
1242
+ import path6 from "path";
863
1243
  import fs4 from "fs/promises";
864
1244
  import {
865
1245
  loadAssetCard as loadAssetCard2,
866
- classifyRisk as classifyRisk2
1246
+ classifyRisk as classifyRisk2,
1247
+ extractGoldenThreadComponents,
1248
+ verifyGoldenThreadHashSync
867
1249
  } from "@aigrc/core";
868
1250
  var DEFAULT_CARDS_DIR4 = ".aigrc/cards";
869
1251
  var DEFAULT_CONFIG_FILE2 = ".aigrc.yaml";
@@ -875,14 +1257,14 @@ async function runStatus(options) {
875
1257
  if (options.output === "text") {
876
1258
  printHeader();
877
1259
  }
878
- const configPath = path5.join(cwd, DEFAULT_CONFIG_FILE2);
879
- const cardsDir = path5.join(cwd, DEFAULT_CARDS_DIR4);
1260
+ const configPath = path6.join(cwd, DEFAULT_CONFIG_FILE2);
1261
+ const cardsDir = path6.join(cwd, DEFAULT_CARDS_DIR4);
880
1262
  const configExists = await fileExists2(configPath);
881
1263
  const cardsDirExists = await directoryExists(cardsDir);
882
1264
  if (!configExists && !cardsDirExists) {
883
1265
  if (options.output === "text") {
884
- console.log(chalk6.yellow("AIGRC is not initialized in this directory."));
885
- console.log(chalk6.dim("\nRun `aigrc init` to get started."));
1266
+ console.log(chalk7.yellow("AIGRC is not initialized in this directory."));
1267
+ console.log(chalk7.dim("\nRun `aigrc init` to get started."));
886
1268
  } else {
887
1269
  console.log(JSON.stringify({ initialized: false }));
888
1270
  }
@@ -895,7 +1277,7 @@ async function runStatus(options) {
895
1277
  const yamlFiles = files.filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
896
1278
  for (const file of yamlFiles) {
897
1279
  try {
898
- const filePath = path5.join(cardsDir, file);
1280
+ const filePath = path6.join(cardsDir, file);
899
1281
  const card = loadAssetCard2(filePath);
900
1282
  const classification = classifyRisk2(card.classification.riskFactors);
901
1283
  cards.push({ path: filePath, card, classification });
@@ -926,19 +1308,21 @@ async function runStatus(options) {
926
1308
  );
927
1309
  return;
928
1310
  }
929
- console.log(chalk6.bold("AIGRC Status"));
930
- console.log(chalk6.dim("\u2500".repeat(50)));
1311
+ console.log(chalk7.bold("AIGRC Status"));
1312
+ console.log(chalk7.dim("\u2500".repeat(50)));
1313
+ console.log();
1314
+ console.log(chalk7.dim("Config:"), configExists ? chalk7.green("\u2713") : chalk7.red("\u2717"), configPath);
1315
+ console.log(chalk7.dim("Cards:"), cardsDirExists ? chalk7.green("\u2713") : chalk7.red("\u2717"), cardsDir);
931
1316
  console.log();
932
- console.log(chalk6.dim("Config:"), configExists ? chalk6.green("\u2713") : chalk6.red("\u2717"), configPath);
933
- console.log(chalk6.dim("Cards:"), cardsDirExists ? chalk6.green("\u2713") : chalk6.red("\u2717"), cardsDir);
1317
+ printGoldenThreadStatus(cards);
934
1318
  console.log();
935
1319
  if (cards.length === 0) {
936
- console.log(chalk6.yellow("No asset cards registered."));
937
- console.log(chalk6.dim("\nRun `aigrc init` or `aigrc register` to create an asset card."));
1320
+ console.log(chalk7.yellow("No asset cards registered."));
1321
+ console.log(chalk7.dim("\nRun `aigrc init` or `aigrc register` to create an asset card."));
938
1322
  return;
939
1323
  }
940
- console.log(chalk6.bold(`Registered Assets (${cards.length})`));
941
- console.log(chalk6.dim("\u2500".repeat(50)));
1324
+ console.log(chalk7.bold(`Registered Assets (${cards.length})`));
1325
+ console.log(chalk7.dim("\u2500".repeat(50)));
942
1326
  console.log();
943
1327
  const byLevel = groupByRiskLevel(cards);
944
1328
  for (const level of ["unacceptable", "high", "limited", "minimal"]) {
@@ -948,18 +1332,18 @@ async function runStatus(options) {
948
1332
  console.log(levelColor(`${level.toUpperCase()} (${levelCards.length})`));
949
1333
  console.log();
950
1334
  for (const { card, classification } of levelCards) {
951
- console.log(` ${chalk6.bold(card.name)}`);
952
- console.log(chalk6.dim(` ID: ${card.id}`));
953
- console.log(chalk6.dim(` Risk Level: ${classification.riskLevel}`));
1335
+ console.log(` ${chalk7.bold(card.name)}`);
1336
+ console.log(chalk7.dim(` ID: ${card.id}`));
1337
+ console.log(chalk7.dim(` Risk Level: ${classification.riskLevel}`));
954
1338
  if (classification.euAiActCategory) {
955
- console.log(chalk6.dim(` EU AI Act: `) + chalk6.yellow(classification.euAiActCategory));
1339
+ console.log(chalk7.dim(` EU AI Act: `) + chalk7.yellow(classification.euAiActCategory));
956
1340
  }
957
1341
  if (card.ownership?.owner) {
958
- console.log(chalk6.dim(` Owner: ${card.ownership.owner.name} <${card.ownership.owner.email}>`));
1342
+ console.log(chalk7.dim(` Owner: ${card.ownership.owner.name} <${card.ownership.owner.email}>`));
959
1343
  }
960
1344
  const activeRisks = getActiveRiskFactors(card);
961
1345
  if (activeRisks.length > 0) {
962
- console.log(chalk6.dim(` Risks: `) + activeRisks.join(", "));
1346
+ console.log(chalk7.dim(` Risks: `) + activeRisks.join(", "));
963
1347
  }
964
1348
  console.log();
965
1349
  }
@@ -978,17 +1362,17 @@ function groupByRiskLevel(cards) {
978
1362
  return byLevel;
979
1363
  }
980
1364
  function printStatusSummary(cards) {
981
- console.log(chalk6.dim("\u2500".repeat(50)));
1365
+ console.log(chalk7.dim("\u2500".repeat(50)));
982
1366
  const minimal = cards.filter((c) => c.classification.riskLevel === "minimal").length;
983
1367
  const limited = cards.filter((c) => c.classification.riskLevel === "limited").length;
984
1368
  const high = cards.filter((c) => c.classification.riskLevel === "high").length;
985
1369
  const unacceptable = cards.filter((c) => c.classification.riskLevel === "unacceptable").length;
986
1370
  console.log(
987
- `Total: ${cards.length} | ` + chalk6.green(`Minimal: ${minimal}`) + ` | ` + chalk6.yellow(`Limited: ${limited}`) + ` | ` + chalk6.red(`High: ${high}`) + ` | ` + chalk6.magenta(`Unacceptable: ${unacceptable}`)
1371
+ `Total: ${cards.length} | ` + chalk7.green(`Minimal: ${minimal}`) + ` | ` + chalk7.yellow(`Limited: ${limited}`) + ` | ` + chalk7.red(`High: ${high}`) + ` | ` + chalk7.magenta(`Unacceptable: ${unacceptable}`)
988
1372
  );
989
1373
  if (high > 0 || unacceptable > 0) {
990
1374
  console.log();
991
- console.log(chalk6.yellow("\u26A0 High-risk assets detected. Review compliance requirements."));
1375
+ console.log(chalk7.yellow("\u26A0 High-risk assets detected. Review compliance requirements."));
992
1376
  }
993
1377
  }
994
1378
  function getActiveRiskFactors(card) {
@@ -1006,15 +1390,15 @@ function getActiveRiskFactors(card) {
1006
1390
  function getRiskLevelColor2(level) {
1007
1391
  switch (level) {
1008
1392
  case "minimal":
1009
- return chalk6.green;
1393
+ return chalk7.green;
1010
1394
  case "limited":
1011
- return chalk6.yellow;
1395
+ return chalk7.yellow;
1012
1396
  case "high":
1013
- return chalk6.red;
1397
+ return chalk7.red;
1014
1398
  case "unacceptable":
1015
- return chalk6.magenta;
1399
+ return chalk7.magenta;
1016
1400
  default:
1017
- return chalk6.white;
1401
+ return chalk7.white;
1018
1402
  }
1019
1403
  }
1020
1404
  async function fileExists2(filePath) {
@@ -1033,14 +1417,296 @@ async function directoryExists(dirPath) {
1033
1417
  return false;
1034
1418
  }
1035
1419
  }
1420
+ function printGoldenThreadStatus(cards) {
1421
+ const cardsWithGoldenThread = cards.filter((c) => {
1422
+ const components = extractGoldenThreadComponents(c.card);
1423
+ return components && c.card.golden_thread?.hash;
1424
+ });
1425
+ if (cardsWithGoldenThread.length === 0) {
1426
+ return;
1427
+ }
1428
+ console.log(chalk7.bold("Golden Thread"));
1429
+ console.log(chalk7.dim("\u2500".repeat(50)));
1430
+ console.log();
1431
+ for (const { card } of cardsWithGoldenThread) {
1432
+ const components = extractGoldenThreadComponents(card);
1433
+ if (!components || !card.golden_thread?.hash) continue;
1434
+ console.log(chalk7.bold(card.name));
1435
+ console.log(chalk7.dim(` Hash: ${card.golden_thread.hash}`));
1436
+ try {
1437
+ const verification = verifyGoldenThreadHashSync(components, card.golden_thread.hash);
1438
+ if (verification.verified) {
1439
+ console.log(chalk7.dim(" Status: ") + chalk7.green("\u2713 Verified"));
1440
+ } else {
1441
+ console.log(chalk7.dim(" Status: ") + chalk7.red("\u2717 Verification Failed"));
1442
+ if (verification.mismatch_reason) {
1443
+ console.log(chalk7.dim(" Reason: ") + chalk7.yellow(verification.mismatch_reason));
1444
+ }
1445
+ }
1446
+ } catch (error) {
1447
+ console.log(chalk7.dim(" Status: ") + chalk7.red("\u2717 Error"));
1448
+ }
1449
+ if (card.golden_thread?.signature) {
1450
+ console.log(chalk7.dim(" Signature: ") + chalk7.green("\u2713 RSA-SHA256"));
1451
+ }
1452
+ console.log();
1453
+ }
1454
+ }
1036
1455
 
1037
- // src/commands/compliance.ts
1456
+ // src/commands/hash.ts
1038
1457
  import { Command as Command6 } from "commander";
1039
- import chalk7 from "chalk";
1458
+ import chalk8 from "chalk";
1040
1459
  import ora4 from "ora";
1460
+ import path7 from "path";
1461
+ import {
1462
+ loadAssetCard as loadAssetCard3,
1463
+ extractGoldenThreadComponents as extractGoldenThreadComponents2,
1464
+ computeGoldenThreadHashSync,
1465
+ verifyGoldenThreadHashSync as verifyGoldenThreadHashSync2,
1466
+ computeCanonicalString
1467
+ } from "@aigrc/core";
1468
+ var hashCommand = new Command6("hash").description("Compute or verify Golden Thread hashes").argument("[path]", "Path to asset card file").option("-v, --verify", "Verify the hash in the asset card").option("-o, --output <format>", "Output format (text, json)", "text").option("--ticket-id <id>", "Ticket ID for manual hash computation").option("--approved-by <email>", "Approver email for manual hash computation").option("--approved-at <datetime>", "Approval timestamp (ISO 8601) for manual hash computation").action(async (cardPath, options) => {
1469
+ await runHash(cardPath, options);
1470
+ });
1471
+ async function runHash(cardPath, options) {
1472
+ if (options.output === "text") {
1473
+ printHeader();
1474
+ }
1475
+ if (options.ticketId && options.approvedBy && options.approvedAt) {
1476
+ await runManualHash(options);
1477
+ return;
1478
+ }
1479
+ if (!cardPath) {
1480
+ if (options.output === "json") {
1481
+ console.log(JSON.stringify({
1482
+ success: false,
1483
+ error: "No asset card path provided. Use --ticket-id, --approved-by, --approved-at for manual computation."
1484
+ }));
1485
+ } else {
1486
+ console.log(chalk8.red("Error: No asset card path provided."));
1487
+ console.log(chalk8.gray("Usage: aigrc hash <path-to-card>"));
1488
+ console.log(chalk8.gray(" or: aigrc hash --ticket-id <id> --approved-by <email> --approved-at <datetime>"));
1489
+ }
1490
+ process.exit(1);
1491
+ }
1492
+ const spinner = options.output === "text" ? ora4("Loading asset card...").start() : null;
1493
+ try {
1494
+ const resolvedPath = path7.resolve(process.cwd(), cardPath);
1495
+ const asset = loadAssetCard3(resolvedPath);
1496
+ spinner?.succeed("Asset card loaded");
1497
+ const components = extractGoldenThreadComponents2(asset);
1498
+ if (!components) {
1499
+ const result = {
1500
+ success: false,
1501
+ error: "Asset card does not have Golden Thread components (missing ticket_id, approved_by, or approved_at)"
1502
+ };
1503
+ outputResult(result, options.output);
1504
+ process.exit(1);
1505
+ }
1506
+ if (options.verify) {
1507
+ await runVerify(components, asset.golden_thread?.hash, options);
1508
+ } else {
1509
+ await runCompute(components, options);
1510
+ }
1511
+ } catch (error) {
1512
+ spinner?.fail("Failed to load asset card");
1513
+ const result = {
1514
+ success: false,
1515
+ error: error instanceof Error ? error.message : String(error)
1516
+ };
1517
+ outputResult(result, options.output);
1518
+ process.exit(1);
1519
+ }
1520
+ }
1521
+ async function runManualHash(options) {
1522
+ const components = {
1523
+ ticket_id: options.ticketId,
1524
+ approved_by: options.approvedBy,
1525
+ approved_at: options.approvedAt
1526
+ };
1527
+ const spinner = options.output === "text" ? ora4("Computing hash...").start() : null;
1528
+ try {
1529
+ const { canonical_string, hash } = computeGoldenThreadHashSync(components);
1530
+ spinner?.succeed("Hash computed");
1531
+ const result = {
1532
+ success: true,
1533
+ canonical_string,
1534
+ hash
1535
+ };
1536
+ outputResult(result, options.output);
1537
+ } catch (error) {
1538
+ spinner?.fail("Failed to compute hash");
1539
+ const result = {
1540
+ success: false,
1541
+ error: error instanceof Error ? error.message : String(error)
1542
+ };
1543
+ outputResult(result, options.output);
1544
+ process.exit(1);
1545
+ }
1546
+ }
1547
+ async function runCompute(components, options) {
1548
+ const spinner = options.output === "text" ? ora4("Computing hash...").start() : null;
1549
+ try {
1550
+ const { canonical_string, hash } = computeGoldenThreadHashSync(components);
1551
+ spinner?.succeed("Hash computed");
1552
+ const result = {
1553
+ success: true,
1554
+ canonical_string,
1555
+ hash
1556
+ };
1557
+ outputResult(result, options.output);
1558
+ } catch (error) {
1559
+ spinner?.fail("Failed to compute hash");
1560
+ const result = {
1561
+ success: false,
1562
+ error: error instanceof Error ? error.message : String(error)
1563
+ };
1564
+ outputResult(result, options.output);
1565
+ process.exit(1);
1566
+ }
1567
+ }
1568
+ async function runVerify(components, expectedHash, options) {
1569
+ const spinner = options.output === "text" ? ora4("Verifying hash...").start() : null;
1570
+ if (!expectedHash) {
1571
+ spinner?.fail("No hash to verify");
1572
+ const result = {
1573
+ success: false,
1574
+ error: "Asset card does not have a hash in golden_thread.hash"
1575
+ };
1576
+ outputResult(result, options.output);
1577
+ process.exit(1);
1578
+ }
1579
+ try {
1580
+ const verification = verifyGoldenThreadHashSync2(components, expectedHash);
1581
+ if (verification.verified) {
1582
+ spinner?.succeed("Hash verified successfully");
1583
+ } else {
1584
+ spinner?.fail("Hash verification failed");
1585
+ }
1586
+ const result = {
1587
+ success: verification.verified,
1588
+ canonical_string: computeCanonicalString(components),
1589
+ hash: verification.computed,
1590
+ verified: verification.verified,
1591
+ expected_hash: verification.expected,
1592
+ error: verification.mismatch_reason
1593
+ };
1594
+ outputResult(result, options.output);
1595
+ if (!verification.verified) {
1596
+ process.exit(1);
1597
+ }
1598
+ } catch (error) {
1599
+ spinner?.fail("Failed to verify hash");
1600
+ const result = {
1601
+ success: false,
1602
+ error: error instanceof Error ? error.message : String(error)
1603
+ };
1604
+ outputResult(result, options.output);
1605
+ process.exit(1);
1606
+ }
1607
+ }
1608
+ function outputResult(result, format) {
1609
+ if (format === "json") {
1610
+ console.log(JSON.stringify(result, null, 2));
1611
+ return;
1612
+ }
1613
+ if (result.success) {
1614
+ if (result.verified !== void 0) {
1615
+ if (result.verified) {
1616
+ console.log(chalk8.green("\u2713 Golden Thread hash verified"));
1617
+ } else {
1618
+ console.log(chalk8.red("\u2717 Golden Thread hash verification failed"));
1619
+ if (result.expected_hash) {
1620
+ console.log(chalk8.dim(`Expected: ${result.expected_hash}`));
1621
+ }
1622
+ if (result.hash) {
1623
+ console.log(chalk8.dim(`Computed: ${result.hash}`));
1624
+ }
1625
+ }
1626
+ } else {
1627
+ if (result.hash) {
1628
+ console.log(result.hash);
1629
+ }
1630
+ }
1631
+ } else {
1632
+ console.log(chalk8.red("Error: ") + result.error);
1633
+ }
1634
+ }
1635
+
1636
+ // src/commands/version.ts
1637
+ import { Command as Command7 } from "commander";
1638
+ import chalk9 from "chalk";
1639
+ import fs5 from "fs/promises";
1640
+ import path8 from "path";
1641
+ var versionCommand = new Command7("version").description("Show version information for AIGRC CLI and packages").option("--json", "Output version information as JSON").action(async (options) => {
1642
+ await runVersion(options);
1643
+ });
1644
+ async function runVersion(options) {
1645
+ const versionInfo = await getVersionInfo();
1646
+ if (options.json) {
1647
+ console.log(JSON.stringify(versionInfo, null, 2));
1648
+ } else {
1649
+ printVersionText(versionInfo);
1650
+ }
1651
+ }
1652
+ async function getVersionInfo() {
1653
+ const cliVersion = await getPackageVersion("@aigrc/cli");
1654
+ const coreVersion = await getPackageVersion("@aigrc/core");
1655
+ const nodeVersion = process.version.replace("v", "");
1656
+ const platform = process.platform;
1657
+ const arch = process.arch;
1658
+ return {
1659
+ cli: cliVersion,
1660
+ core: coreVersion,
1661
+ node: nodeVersion,
1662
+ platform,
1663
+ arch
1664
+ };
1665
+ }
1666
+ async function getPackageVersion(packageName) {
1667
+ try {
1668
+ const pkgPath = __require.resolve(`${packageName}/package.json`);
1669
+ const pkgContent = await fs5.readFile(pkgPath, "utf-8");
1670
+ const pkg = JSON.parse(pkgContent);
1671
+ return pkg.version || "unknown";
1672
+ } catch {
1673
+ try {
1674
+ const currentPkgPath = path8.join(process.cwd(), "package.json");
1675
+ const pkgContent = await fs5.readFile(currentPkgPath, "utf-8");
1676
+ const pkg = JSON.parse(pkgContent);
1677
+ if (pkg.name === packageName) {
1678
+ return pkg.version || "unknown";
1679
+ }
1680
+ if (pkg.dependencies?.[packageName]) {
1681
+ return pkg.dependencies[packageName].replace("^", "").replace("~", "");
1682
+ }
1683
+ if (pkg.devDependencies?.[packageName]) {
1684
+ return pkg.devDependencies[packageName].replace("^", "").replace("~", "");
1685
+ }
1686
+ } catch {
1687
+ }
1688
+ return "unknown";
1689
+ }
1690
+ }
1691
+ function printVersionText(info) {
1692
+ console.log();
1693
+ console.log(chalk9.cyan.bold("AIGRC Version Information"));
1694
+ console.log(chalk9.dim("\u2500".repeat(50)));
1695
+ console.log();
1696
+ console.log(`${chalk9.dim("aigrc CLI:")} ${chalk9.bold(info.cli)}`);
1697
+ console.log(`${chalk9.dim("@aigrc/core:")} ${chalk9.bold(info.core)}`);
1698
+ console.log(`${chalk9.dim("Node.js:")} ${chalk9.bold("v" + info.node)}`);
1699
+ console.log(`${chalk9.dim("Platform:")} ${chalk9.bold(info.platform + " " + info.arch)}`);
1700
+ console.log();
1701
+ }
1702
+
1703
+ // src/commands/compliance.ts
1704
+ import { Command as Command8 } from "commander";
1705
+ import chalk10 from "chalk";
1706
+ import ora5 from "ora";
1041
1707
  import { existsSync, readFileSync, writeFileSync } from "fs";
1042
1708
  import { join } from "path";
1043
- import YAML from "yaml";
1709
+ import YAML2 from "yaml";
1044
1710
  var BUILTIN_PROFILES = [
1045
1711
  {
1046
1712
  id: "eu-ai-act",
@@ -1071,16 +1737,16 @@ var BUILTIN_PROFILES = [
1071
1737
  description: "AI Management System Standard"
1072
1738
  }
1073
1739
  ];
1074
- var complianceCommand = new Command6("compliance").description("Manage compliance profiles").addCommand(
1075
- new Command6("list").description("List available compliance profiles").option("-a, --active", "Show only active profiles").option("-o, --output <format>", "Output format (text, json, yaml)", "text").action(async (options) => {
1740
+ var complianceCommand = new Command8("compliance").description("Manage compliance profiles").addCommand(
1741
+ new Command8("list").description("List available compliance profiles").option("-a, --active", "Show only active profiles").option("-o, --output <format>", "Output format (text, json, yaml)", "text").action(async (options) => {
1076
1742
  await listProfiles(options);
1077
1743
  })
1078
1744
  ).addCommand(
1079
- new Command6("show").description("Show details of a profile").argument("<profileId>", "Profile ID (e.g., eu-ai-act, us-omb-m24)").option("-o, --output <format>", "Output format (text, json, yaml)", "text").action(async (profileId, options) => {
1745
+ new Command8("show").description("Show details of a profile").argument("<profileId>", "Profile ID (e.g., eu-ai-act, us-omb-m24)").option("-o, --output <format>", "Output format (text, json, yaml)", "text").action(async (profileId, options) => {
1080
1746
  await showProfile(profileId, options);
1081
1747
  })
1082
1748
  ).addCommand(
1083
- new Command6("set").description("Set active profiles in .aigrc.yaml").argument("<profiles...>", "Profile IDs to activate").option("--stack", "Enable profile stacking (strictest wins)").action(async (profiles, options) => {
1749
+ new Command8("set").description("Set active profiles in .aigrc.yaml").argument("<profiles...>", "Profile IDs to activate").option("--stack", "Enable profile stacking (strictest wins)").action(async (profiles, options) => {
1084
1750
  await setProfiles(profiles, options);
1085
1751
  })
1086
1752
  );
@@ -1096,19 +1762,19 @@ async function listProfiles(options) {
1096
1762
  return;
1097
1763
  }
1098
1764
  if (options.output === "yaml") {
1099
- console.log(YAML.stringify(profiles));
1765
+ console.log(YAML2.stringify(profiles));
1100
1766
  return;
1101
1767
  }
1102
1768
  console.log();
1103
1769
  console.log(
1104
- chalk7.dim(" ID".padEnd(16)) + chalk7.dim("Name".padEnd(28)) + chalk7.dim("Jurisdiction".padEnd(16)) + chalk7.dim("Active")
1770
+ chalk10.dim(" ID".padEnd(16)) + chalk10.dim("Name".padEnd(28)) + chalk10.dim("Jurisdiction".padEnd(16)) + chalk10.dim("Active")
1105
1771
  );
1106
- console.log(chalk7.dim(" " + "\u2500".repeat(70)));
1772
+ console.log(chalk10.dim(" " + "\u2500".repeat(70)));
1107
1773
  for (const profile of profiles) {
1108
1774
  const isActive = activeProfiles.includes(profile.id);
1109
- const activeIndicator = isActive ? chalk7.green("\u2713") : chalk7.gray("\xB7");
1775
+ const activeIndicator = isActive ? chalk10.green("\u2713") : chalk10.gray("\xB7");
1110
1776
  console.log(
1111
- ` ${chalk7.cyan(profile.id.padEnd(14))} ${profile.name.padEnd(26)} ${chalk7.dim(profile.jurisdiction.padEnd(14))} ${activeIndicator}`
1777
+ ` ${chalk10.cyan(profile.id.padEnd(14))} ${profile.name.padEnd(26)} ${chalk10.dim(profile.jurisdiction.padEnd(14))} ${activeIndicator}`
1112
1778
  );
1113
1779
  }
1114
1780
  console.log();
@@ -1127,21 +1793,21 @@ async function showProfile(profileId, options) {
1127
1793
  return;
1128
1794
  }
1129
1795
  if (options.output === "yaml") {
1130
- console.log(YAML.stringify(profile));
1796
+ console.log(YAML2.stringify(profile));
1131
1797
  return;
1132
1798
  }
1133
1799
  printHeader();
1134
- console.log(chalk7.bold.cyan(`Profile: ${profile.name}`));
1800
+ console.log(chalk10.bold.cyan(`Profile: ${profile.name}`));
1135
1801
  console.log();
1136
- console.log(` ${chalk7.dim("ID:")} ${profile.id}`);
1137
- console.log(` ${chalk7.dim("Version:")} ${profile.version}`);
1138
- console.log(` ${chalk7.dim("Jurisdiction:")} ${profile.jurisdiction}`);
1139
- console.log(` ${chalk7.dim("Description:")} ${profile.description}`);
1802
+ console.log(` ${chalk10.dim("ID:")} ${profile.id}`);
1803
+ console.log(` ${chalk10.dim("Version:")} ${profile.version}`);
1804
+ console.log(` ${chalk10.dim("Jurisdiction:")} ${profile.jurisdiction}`);
1805
+ console.log(` ${chalk10.dim("Description:")} ${profile.description}`);
1140
1806
  const activeProfiles = loadActiveProfiles();
1141
1807
  const isActive = activeProfiles.includes(profile.id);
1142
1808
  console.log();
1143
1809
  console.log(
1144
- ` ${chalk7.dim("Status:")} ${isActive ? chalk7.green("Active") : chalk7.gray("Inactive")}`
1810
+ ` ${chalk10.dim("Status:")} ${isActive ? chalk10.green("Active") : chalk10.gray("Inactive")}`
1145
1811
  );
1146
1812
  }
1147
1813
  async function setProfiles(profiles, options) {
@@ -1155,19 +1821,19 @@ async function setProfiles(profiles, options) {
1155
1821
  printInfo(`Available profiles: ${BUILTIN_PROFILES.map((p) => p.id).join(", ")}`);
1156
1822
  process.exit(1);
1157
1823
  }
1158
- const spinner = ora4("Updating configuration...").start();
1824
+ const spinner = ora5("Updating configuration...").start();
1159
1825
  try {
1160
1826
  const configPath = join(process.cwd(), ".aigrc.yaml");
1161
1827
  let config = {};
1162
1828
  if (existsSync(configPath)) {
1163
1829
  const content = readFileSync(configPath, "utf-8");
1164
- config = YAML.parse(content) || {};
1830
+ config = YAML2.parse(content) || {};
1165
1831
  }
1166
1832
  config.profiles = profiles;
1167
1833
  if (options.stack) {
1168
1834
  config.stackProfiles = true;
1169
1835
  }
1170
- writeFileSync(configPath, YAML.stringify(config, { indent: 2 }), "utf-8");
1836
+ writeFileSync(configPath, YAML2.stringify(config, { indent: 2 }), "utf-8");
1171
1837
  spinner.succeed("Configuration updated");
1172
1838
  console.log();
1173
1839
  printSuccess(`Active profiles: ${profiles.join(", ")}`);
@@ -1187,7 +1853,7 @@ function loadActiveProfiles() {
1187
1853
  }
1188
1854
  try {
1189
1855
  const content = readFileSync(configPath, "utf-8");
1190
- const config = YAML.parse(content);
1856
+ const config = YAML2.parse(content);
1191
1857
  return config?.profiles || ["eu-ai-act"];
1192
1858
  } catch {
1193
1859
  return ["eu-ai-act"];
@@ -1195,13 +1861,13 @@ function loadActiveProfiles() {
1195
1861
  }
1196
1862
 
1197
1863
  // src/commands/classify.ts
1198
- import { Command as Command7 } from "commander";
1199
- import chalk8 from "chalk";
1200
- import ora5 from "ora";
1864
+ import { Command as Command9 } from "commander";
1865
+ import chalk11 from "chalk";
1866
+ import ora6 from "ora";
1201
1867
  import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
1202
1868
  import { join as join2 } from "path";
1203
- import YAML2 from "yaml";
1204
- import { loadAssetCard as loadAssetCard3, saveAssetCard as saveAssetCard3 } from "@aigrc/core";
1869
+ import YAML3 from "yaml";
1870
+ import { loadAssetCard as loadAssetCard4, saveAssetCard as saveAssetCard3 } from "@aigrc/core";
1205
1871
  var RISK_MAPPINGS = {
1206
1872
  "eu-ai-act": {
1207
1873
  minimal: "minimal",
@@ -1234,7 +1900,7 @@ var PROFILE_NAMES = {
1234
1900
  "nist-ai-rmf": "NIST AI RMF",
1235
1901
  "iso-42001": "ISO/IEC 42001"
1236
1902
  };
1237
- var classifyCommand = new Command7("classify").description("Classify an asset against compliance profiles").argument("<assetPath>", "Path to asset card YAML file").option("-p, --profiles <profiles...>", "Profile IDs to classify against").option("-a, --all", "Classify against all available profiles").option("-o, --output <format>", "Output format (text, json, yaml)", "text").option("-u, --update", "Update asset card with classification results").action(async (assetPath, options) => {
1903
+ var classifyCommand = new Command9("classify").description("Classify an asset against compliance profiles").argument("<assetPath>", "Path to asset card YAML file").option("-p, --profiles <profiles...>", "Profile IDs to classify against").option("-a, --all", "Classify against all available profiles").option("-o, --output <format>", "Output format (text, json, yaml)", "text").option("-u, --update", "Update asset card with classification results").action(async (assetPath, options) => {
1238
1904
  await runClassify(assetPath, options);
1239
1905
  });
1240
1906
  async function runClassify(assetPath, options) {
@@ -1245,10 +1911,10 @@ async function runClassify(assetPath, options) {
1245
1911
  printError(`Asset card not found: ${assetPath}`);
1246
1912
  process.exit(1);
1247
1913
  }
1248
- const spinner = ora5("Loading asset card...").start();
1914
+ const spinner = ora6("Loading asset card...").start();
1249
1915
  let card;
1250
1916
  try {
1251
- card = loadAssetCard3(assetPath);
1917
+ card = loadAssetCard4(assetPath);
1252
1918
  spinner.succeed(`Loaded: ${card.name}`);
1253
1919
  } catch (error) {
1254
1920
  spinner.fail("Failed to load asset card");
@@ -1296,7 +1962,7 @@ async function runClassify(assetPath, options) {
1296
1962
  }
1297
1963
  if (options.output === "yaml") {
1298
1964
  console.log(
1299
- YAML2.stringify({
1965
+ YAML3.stringify({
1300
1966
  asset: card.name,
1301
1967
  aigrcRiskLevel: aigrcLevel,
1302
1968
  classifications
@@ -1307,12 +1973,12 @@ async function runClassify(assetPath, options) {
1307
1973
  console.log();
1308
1974
  printSubheader(`Classification: ${card.name}`);
1309
1975
  console.log();
1310
- console.log(` ${chalk8.dim("AIGRC Risk Level:")} ${formatRiskLevel(aigrcLevel)}`);
1976
+ console.log(` ${chalk11.dim("AIGRC Risk Level:")} ${formatRiskLevel(aigrcLevel)}`);
1311
1977
  console.log();
1312
1978
  console.log(
1313
- chalk8.dim(" Profile".padEnd(24)) + chalk8.dim("Mapped Risk Level")
1979
+ chalk11.dim(" Profile".padEnd(24)) + chalk11.dim("Mapped Risk Level")
1314
1980
  );
1315
- console.log(chalk8.dim(" " + "\u2500".repeat(50)));
1981
+ console.log(chalk11.dim(" " + "\u2500".repeat(50)));
1316
1982
  for (const c of classifications) {
1317
1983
  console.log(
1318
1984
  ` ${c.profileName.padEnd(22)} ${formatRiskLevel(c.mappedLevel)}`
@@ -1329,9 +1995,9 @@ async function runClassify(assetPath, options) {
1329
1995
  }
1330
1996
  }
1331
1997
  console.log();
1332
- console.log(` ${chalk8.dim("Strictest:")} ${formatRiskLevel(strictestLevel)}`);
1998
+ console.log(` ${chalk11.dim("Strictest:")} ${formatRiskLevel(strictestLevel)}`);
1333
1999
  if (options.update) {
1334
- const updateSpinner = ora5("Updating asset card...").start();
2000
+ const updateSpinner = ora6("Updating asset card...").start();
1335
2001
  try {
1336
2002
  const jurisdictions = classifications.map((c) => ({
1337
2003
  jurisdictionId: c.profileId,
@@ -1349,19 +2015,19 @@ async function runClassify(assetPath, options) {
1349
2015
  }
1350
2016
  function formatRiskLevel(level) {
1351
2017
  const colors = {
1352
- minimal: chalk8.green,
1353
- neither: chalk8.green,
1354
- low: chalk8.green,
1355
- limited: chalk8.yellow,
1356
- medium: chalk8.yellow,
1357
- moderate: chalk8.yellow,
1358
- high: chalk8.red,
1359
- "rights-impacting": chalk8.red,
1360
- critical: chalk8.magenta,
1361
- "safety-impacting": chalk8.magenta,
1362
- unacceptable: chalk8.magenta.bold
2018
+ minimal: chalk11.green,
2019
+ neither: chalk11.green,
2020
+ low: chalk11.green,
2021
+ limited: chalk11.yellow,
2022
+ medium: chalk11.yellow,
2023
+ moderate: chalk11.yellow,
2024
+ high: chalk11.red,
2025
+ "rights-impacting": chalk11.red,
2026
+ critical: chalk11.magenta,
2027
+ "safety-impacting": chalk11.magenta,
2028
+ unacceptable: chalk11.magenta.bold
1363
2029
  };
1364
- const colorFn = colors[level] || chalk8.white;
2030
+ const colorFn = colors[level] || chalk11.white;
1365
2031
  return colorFn(level.toUpperCase());
1366
2032
  }
1367
2033
  function loadActiveProfiles2() {
@@ -1371,7 +2037,7 @@ function loadActiveProfiles2() {
1371
2037
  }
1372
2038
  try {
1373
2039
  const content = readFileSync2(configPath, "utf-8");
1374
- const config = YAML2.parse(content);
2040
+ const config = YAML3.parse(content);
1375
2041
  return config?.profiles || ["eu-ai-act"];
1376
2042
  } catch {
1377
2043
  return ["eu-ai-act"];
@@ -1379,13 +2045,13 @@ function loadActiveProfiles2() {
1379
2045
  }
1380
2046
 
1381
2047
  // src/commands/check.ts
1382
- import { Command as Command8 } from "commander";
1383
- import chalk9 from "chalk";
1384
- import ora6 from "ora";
2048
+ import { Command as Command10 } from "commander";
2049
+ import chalk12 from "chalk";
2050
+ import ora7 from "ora";
1385
2051
  import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
1386
2052
  import { join as join3 } from "path";
1387
- import YAML3 from "yaml";
1388
- import { loadAssetCard as loadAssetCard4 } from "@aigrc/core";
2053
+ import YAML4 from "yaml";
2054
+ import { loadAssetCard as loadAssetCard5 } from "@aigrc/core";
1389
2055
  var PROFILE_CONTROLS = {
1390
2056
  "eu-ai-act": [
1391
2057
  { id: "eu-art-9", name: "Risk Management System", category: "Risk Management", riskLevels: ["high"] },
@@ -1432,7 +2098,7 @@ var PROFILE_NAMES2 = {
1432
2098
  "nist-ai-rmf": "NIST AI RMF",
1433
2099
  "iso-42001": "ISO/IEC 42001"
1434
2100
  };
1435
- var checkCommand = new Command8("check").description("Check compliance status for an asset").argument("<assetPath>", "Path to asset card YAML file").option("-p, --profiles <profiles...>", "Profile IDs to check").option("-s, --stack", "Check against stacked profiles (strictest wins)").option("-o, --output <format>", "Output format (text, json, yaml)", "text").option("-v, --verbose", "Show detailed control status").action(async (assetPath, options) => {
2101
+ var checkCommand = new Command10("check").description("Check compliance status for an asset").argument("<assetPath>", "Path to asset card YAML file").option("-p, --profiles <profiles...>", "Profile IDs to check").option("-s, --stack", "Check against stacked profiles (strictest wins)").option("-o, --output <format>", "Output format (text, json, yaml)", "text").option("-v, --verbose", "Show detailed control status").action(async (assetPath, options) => {
1436
2102
  await runCheck(assetPath, options);
1437
2103
  });
1438
2104
  async function runCheck(assetPath, options) {
@@ -1443,10 +2109,10 @@ async function runCheck(assetPath, options) {
1443
2109
  printError(`Asset card not found: ${assetPath}`);
1444
2110
  process.exit(1);
1445
2111
  }
1446
- const spinner = ora6("Loading asset card...").start();
2112
+ const spinner = ora7("Loading asset card...").start();
1447
2113
  let card;
1448
2114
  try {
1449
- card = loadAssetCard4(assetPath);
2115
+ card = loadAssetCard5(assetPath);
1450
2116
  spinner.succeed(`Loaded: ${card.name}`);
1451
2117
  } catch (error) {
1452
2118
  spinner.fail("Failed to load asset card");
@@ -1471,19 +2137,19 @@ async function runCheck(assetPath, options) {
1471
2137
  return;
1472
2138
  }
1473
2139
  if (options.output === "yaml") {
1474
- console.log(YAML3.stringify({ asset: card.name, results }));
2140
+ console.log(YAML4.stringify({ asset: card.name, results }));
1475
2141
  return;
1476
2142
  }
1477
2143
  console.log();
1478
2144
  printSubheader(`Compliance Check: ${card.name}`);
1479
2145
  console.log();
1480
2146
  console.log(
1481
- chalk9.dim(" Profile".padEnd(20)) + chalk9.dim("Risk Level".padEnd(20)) + chalk9.dim("Compliant".padEnd(12)) + chalk9.dim("Score")
2147
+ chalk12.dim(" Profile".padEnd(20)) + chalk12.dim("Risk Level".padEnd(20)) + chalk12.dim("Compliant".padEnd(12)) + chalk12.dim("Score")
1482
2148
  );
1483
- console.log(chalk9.dim(" " + "\u2500".repeat(60)));
2149
+ console.log(chalk12.dim(" " + "\u2500".repeat(60)));
1484
2150
  for (const r of results) {
1485
- const compliantIcon = r.compliant ? chalk9.green("\u2713 Yes") : chalk9.red("\u2717 No");
1486
- const scoreColor = r.percentage >= 80 ? chalk9.green : r.percentage >= 50 ? chalk9.yellow : chalk9.red;
2151
+ const compliantIcon = r.compliant ? chalk12.green("\u2713 Yes") : chalk12.red("\u2717 No");
2152
+ const scoreColor = r.percentage >= 80 ? chalk12.green : r.percentage >= 50 ? chalk12.yellow : chalk12.red;
1487
2153
  console.log(
1488
2154
  ` ${r.profileName.padEnd(18)} ${formatRiskLevel2(r.riskLevel).padEnd(28)} ${compliantIcon.padEnd(20)} ${scoreColor(r.percentage + "%")}`
1489
2155
  );
@@ -1493,7 +2159,7 @@ async function runCheck(assetPath, options) {
1493
2159
  const allCompliant = results.every((r) => r.compliant);
1494
2160
  const avgPercentage = Math.round(results.reduce((acc, r) => acc + r.percentage, 0) / results.length);
1495
2161
  console.log(
1496
- ` ${chalk9.bold("STACKED")}`.padEnd(18) + `${chalk9.dim("(strictest)")}`.padEnd(28) + `${allCompliant ? chalk9.green("\u2713 Yes") : chalk9.red("\u2717 No")}`.padEnd(20) + `${avgPercentage}%`
2162
+ ` ${chalk12.bold("STACKED")}`.padEnd(18) + `${chalk12.dim("(strictest)")}`.padEnd(28) + `${allCompliant ? chalk12.green("\u2713 Yes") : chalk12.red("\u2717 No")}`.padEnd(20) + `${avgPercentage}%`
1497
2163
  );
1498
2164
  }
1499
2165
  if (options.verbose) {
@@ -1502,9 +2168,9 @@ async function runCheck(assetPath, options) {
1502
2168
  printSubheader(`${r.profileName} Details`);
1503
2169
  console.log();
1504
2170
  console.log(
1505
- chalk9.dim(" Control".padEnd(32)) + chalk9.dim("Status")
2171
+ chalk12.dim(" Control".padEnd(32)) + chalk12.dim("Status")
1506
2172
  );
1507
- console.log(chalk9.dim(" " + "\u2500".repeat(50)));
2173
+ console.log(chalk12.dim(" " + "\u2500".repeat(50)));
1508
2174
  for (const c of r.controls) {
1509
2175
  const statusIcon = getStatusIcon(c.status);
1510
2176
  console.log(` ${c.controlName.padEnd(30)} ${statusIcon}`);
@@ -1513,7 +2179,7 @@ async function runCheck(assetPath, options) {
1513
2179
  console.log();
1514
2180
  printWarning(`${r.gaps.length} gap(s) identified:`);
1515
2181
  for (const gap of r.gaps) {
1516
- console.log(chalk9.yellow(` - ${gap}`));
2182
+ console.log(chalk12.yellow(` - ${gap}`));
1517
2183
  }
1518
2184
  }
1519
2185
  }
@@ -1575,9 +2241,9 @@ function evaluateControl(card, control) {
1575
2241
  "Risk Management": hasApprovals || hasIntent,
1576
2242
  "Data Governance": hasConstraints,
1577
2243
  Documentation: hasIntent && !!card.intent.businessJustification,
1578
- Logging: hasConstraints && card.constraints?.monitoring?.logAllDecisions,
2244
+ Logging: hasConstraints && !!card.constraints?.monitoring?.logAllDecisions,
1579
2245
  Transparency: card.intent.linked,
1580
- Oversight: hasApprovals || hasConstraints && card.constraints?.humanApprovalRequired?.length,
2246
+ Oversight: hasApprovals || hasConstraints && !!card.constraints?.humanApprovalRequired?.length,
1581
2247
  Technical: hasConstraints,
1582
2248
  Assessment: hasIntent && !!card.intent.businessJustification,
1583
2249
  Governance: hasApprovals,
@@ -1585,12 +2251,12 @@ function evaluateControl(card, control) {
1585
2251
  Leadership: hasApprovals,
1586
2252
  Support: card.ownership.team !== void 0,
1587
2253
  Operations: hasConstraints,
1588
- Performance: hasConstraints && card.constraints?.monitoring?.logAllDecisions,
2254
+ Performance: hasConstraints && !!card.constraints?.monitoring?.logAllDecisions,
1589
2255
  Improvement: hasApprovals && card.governance.status !== "draft",
1590
2256
  Equity: hasIntent && !!card.intent.businessJustification,
1591
2257
  Remediation: hasApprovals,
1592
2258
  Testing: hasConstraints,
1593
- Measurement: hasConstraints && card.constraints?.monitoring,
2259
+ Measurement: hasConstraints && !!card.constraints?.monitoring,
1594
2260
  Management: hasApprovals || hasIntent,
1595
2261
  "Risk Mapping": hasIntent
1596
2262
  };
@@ -1603,30 +2269,30 @@ function evaluateControl(card, control) {
1603
2269
  function getStatusIcon(status) {
1604
2270
  switch (status) {
1605
2271
  case "implemented":
1606
- return chalk9.green("\u2713 Implemented");
2272
+ return chalk12.green("\u2713 Implemented");
1607
2273
  case "partial":
1608
- return chalk9.yellow("\u25D0 Partial");
2274
+ return chalk12.yellow("\u25D0 Partial");
1609
2275
  case "not_implemented":
1610
- return chalk9.red("\u2717 Missing");
2276
+ return chalk12.red("\u2717 Missing");
1611
2277
  case "not_applicable":
1612
- return chalk9.gray("- N/A");
2278
+ return chalk12.gray("- N/A");
1613
2279
  }
1614
2280
  }
1615
2281
  function formatRiskLevel2(level) {
1616
2282
  const colors = {
1617
- minimal: chalk9.green,
1618
- neither: chalk9.green,
1619
- low: chalk9.green,
1620
- limited: chalk9.yellow,
1621
- medium: chalk9.yellow,
1622
- moderate: chalk9.yellow,
1623
- high: chalk9.red,
1624
- "rights-impacting": chalk9.red,
1625
- critical: chalk9.magenta,
1626
- "safety-impacting": chalk9.magenta,
1627
- unacceptable: chalk9.magenta.bold
2283
+ minimal: chalk12.green,
2284
+ neither: chalk12.green,
2285
+ low: chalk12.green,
2286
+ limited: chalk12.yellow,
2287
+ medium: chalk12.yellow,
2288
+ moderate: chalk12.yellow,
2289
+ high: chalk12.red,
2290
+ "rights-impacting": chalk12.red,
2291
+ critical: chalk12.magenta,
2292
+ "safety-impacting": chalk12.magenta,
2293
+ unacceptable: chalk12.magenta.bold
1628
2294
  };
1629
- const colorFn = colors[level] || chalk9.white;
2295
+ const colorFn = colors[level] || chalk12.white;
1630
2296
  return colorFn(level.toUpperCase());
1631
2297
  }
1632
2298
  function loadActiveProfiles3() {
@@ -1636,7 +2302,7 @@ function loadActiveProfiles3() {
1636
2302
  }
1637
2303
  try {
1638
2304
  const content = readFileSync3(configPath, "utf-8");
1639
- const config = YAML3.parse(content);
2305
+ const config = YAML4.parse(content);
1640
2306
  return config?.profiles || ["eu-ai-act"];
1641
2307
  } catch {
1642
2308
  return ["eu-ai-act"];
@@ -1644,12 +2310,12 @@ function loadActiveProfiles3() {
1644
2310
  }
1645
2311
 
1646
2312
  // src/commands/generate.ts
1647
- import { Command as Command9 } from "commander";
1648
- import ora7 from "ora";
2313
+ import { Command as Command11 } from "commander";
2314
+ import ora8 from "ora";
1649
2315
  import { existsSync as existsSync4, mkdirSync, writeFileSync as writeFileSync3, readFileSync as readFileSync4 } from "fs";
1650
2316
  import { join as join4 } from "path";
1651
- import YAML4 from "yaml";
1652
- import { loadAssetCard as loadAssetCard5 } from "@aigrc/core";
2317
+ import YAML5 from "yaml";
2318
+ import { loadAssetCard as loadAssetCard6 } from "@aigrc/core";
1653
2319
  var ARTIFACT_TEMPLATES = {
1654
2320
  "eu-ai-act": [
1655
2321
  { id: "risk-management-plan", name: "Risk Management Plan", requiredFor: ["high"], format: "md" },
@@ -1682,7 +2348,7 @@ var PROFILE_NAMES3 = {
1682
2348
  "nist-ai-rmf": "NIST AI RMF",
1683
2349
  "iso-42001": "ISO/IEC 42001"
1684
2350
  };
1685
- var generateCommand = new Command9("generate").description("Generate compliance artifacts from templates").argument("<assetPath>", "Path to asset card YAML file").option("-p, --profile <profile>", "Profile ID for templates").option("-t, --template <template>", "Specific template ID to generate").option("-a, --all", "Generate all required artifacts").option("-o, --output-dir <dir>", "Output directory", ".aigrc/artifacts").option("-f, --force", "Overwrite existing files").action(async (assetPath, options) => {
2351
+ var generateCommand = new Command11("generate").description("Generate compliance artifacts from templates").argument("<assetPath>", "Path to asset card YAML file").option("-p, --profile <profile>", "Profile ID for templates").option("-t, --template <template>", "Specific template ID to generate").option("-a, --all", "Generate all required artifacts").option("-o, --output-dir <dir>", "Output directory", ".aigrc/artifacts").option("-f, --force", "Overwrite existing files").action(async (assetPath, options) => {
1686
2352
  await runGenerate(assetPath, options);
1687
2353
  });
1688
2354
  async function runGenerate(assetPath, options) {
@@ -1691,10 +2357,10 @@ async function runGenerate(assetPath, options) {
1691
2357
  printError(`Asset card not found: ${assetPath}`);
1692
2358
  process.exit(1);
1693
2359
  }
1694
- const spinner = ora7("Loading asset card...").start();
2360
+ const spinner = ora8("Loading asset card...").start();
1695
2361
  let card;
1696
2362
  try {
1697
- card = loadAssetCard5(assetPath);
2363
+ card = loadAssetCard6(assetPath);
1698
2364
  spinner.succeed(`Loaded: ${card.name}`);
1699
2365
  } catch (error) {
1700
2366
  spinner.fail("Failed to load asset card");
@@ -1859,7 +2525,7 @@ function generateYamlTemplate(card, profileId, template) {
1859
2525
  pendingSections: ["All sections require review"]
1860
2526
  }
1861
2527
  };
1862
- return YAML4.stringify(content, { indent: 2 });
2528
+ return YAML5.stringify(content, { indent: 2 });
1863
2529
  }
1864
2530
  function getSection2Title(templateId) {
1865
2531
  const titles = {
@@ -1950,7 +2616,7 @@ function loadActiveProfiles4() {
1950
2616
  }
1951
2617
  try {
1952
2618
  const content = readFileSync4(configPath, "utf-8");
1953
- const config = YAML4.parse(content);
2619
+ const config = YAML5.parse(content);
1954
2620
  return config?.profiles || ["eu-ai-act"];
1955
2621
  } catch {
1956
2622
  return ["eu-ai-act"];
@@ -1958,12 +2624,12 @@ function loadActiveProfiles4() {
1958
2624
  }
1959
2625
 
1960
2626
  // src/commands/report.ts
1961
- import { Command as Command10 } from "commander";
1962
- import ora8 from "ora";
2627
+ import { Command as Command12 } from "commander";
2628
+ import ora9 from "ora";
1963
2629
  import { existsSync as existsSync5, mkdirSync as mkdirSync2, writeFileSync as writeFileSync4, readFileSync as readFileSync5, readdirSync } from "fs";
1964
2630
  import { join as join5 } from "path";
1965
- import YAML5 from "yaml";
1966
- import { loadAssetCard as loadAssetCard6 } from "@aigrc/core";
2631
+ import YAML6 from "yaml";
2632
+ import { loadAssetCard as loadAssetCard7 } from "@aigrc/core";
1967
2633
  var PROFILE_NAMES4 = {
1968
2634
  "eu-ai-act": "EU AI Act",
1969
2635
  "us-omb-m24": "US OMB M-24",
@@ -2007,26 +2673,26 @@ var CONTROL_CROSSWALK = {
2007
2673
  "iso-42001": ["iso-a8"]
2008
2674
  }
2009
2675
  };
2010
- var reportCommand = new Command10("report").description("Generate compliance reports").addCommand(
2011
- new Command10("gap").description("Generate gap analysis report").argument("[assetPath]", "Path to asset card (or all in .aigrc/cards)").option("-p, --profiles <profiles...>", "Profile IDs to analyze").option("-o, --output <file>", "Output file path").option("-f, --format <format>", "Format (md, json, yaml)", "md").action(async (assetPath, options) => {
2676
+ var reportCommand = new Command12("report").description("Generate compliance reports").addCommand(
2677
+ new Command12("gap").description("Generate gap analysis report").argument("[assetPath]", "Path to asset card (or all in .aigrc/cards)").option("-p, --profiles <profiles...>", "Profile IDs to analyze").option("-o, --output <file>", "Output file path").option("-f, --format <format>", "Format (md, json, yaml)", "md").action(async (assetPath, options) => {
2012
2678
  await generateGapReport(assetPath, options);
2013
2679
  })
2014
2680
  ).addCommand(
2015
- new Command10("crosswalk").description("Generate cross-framework mapping report").argument("<assetPath>", "Path to asset card").option("-p, --profiles <profiles...>", "Profile IDs to include").option("-o, --output <file>", "Output file path").option("-f, --format <format>", "Format (md, json, yaml)", "md").action(async (assetPath, options) => {
2681
+ new Command12("crosswalk").description("Generate cross-framework mapping report").argument("<assetPath>", "Path to asset card").option("-p, --profiles <profiles...>", "Profile IDs to include").option("-o, --output <file>", "Output file path").option("-f, --format <format>", "Format (md, json, yaml)", "md").action(async (assetPath, options) => {
2016
2682
  await generateCrosswalkReport(assetPath, options);
2017
2683
  })
2018
2684
  ).addCommand(
2019
- new Command10("audit").description("Generate audit package").option("-p, --profile <profile>", "Profile ID", "eu-ai-act").option("-o, --output <dir>", "Output directory").option("--include-assets <assets...>", "Specific asset card paths").action(async (options) => {
2685
+ new Command12("audit").description("Generate audit package").option("-p, --profile <profile>", "Profile ID", "eu-ai-act").option("-o, --output <dir>", "Output directory").option("--include-assets <assets...>", "Specific asset card paths").action(async (options) => {
2020
2686
  await generateAuditPackage(options);
2021
2687
  })
2022
2688
  );
2023
2689
  async function generateGapReport(assetPath, options) {
2024
2690
  printHeader();
2025
- const spinner = ora8("Loading assets...").start();
2691
+ const spinner = ora9("Loading assets...").start();
2026
2692
  let cards = [];
2027
2693
  if (assetPath) {
2028
2694
  try {
2029
- const card = loadAssetCard6(assetPath);
2695
+ const card = loadAssetCard7(assetPath);
2030
2696
  cards.push({ path: assetPath, card });
2031
2697
  } catch (error) {
2032
2698
  spinner.fail("Failed to load asset card");
@@ -2039,7 +2705,7 @@ async function generateGapReport(assetPath, options) {
2039
2705
  const files = readdirSync(cardsDir).filter((f) => f.endsWith(".yaml") || f.endsWith(".yml"));
2040
2706
  for (const file of files) {
2041
2707
  try {
2042
- const card = loadAssetCard6(join5(cardsDir, file));
2708
+ const card = loadAssetCard7(join5(cardsDir, file));
2043
2709
  cards.push({ path: join5(cardsDir, file), card });
2044
2710
  } catch {
2045
2711
  }
@@ -2093,7 +2759,7 @@ async function generateGapReport(assetPath, options) {
2093
2759
  return;
2094
2760
  }
2095
2761
  if (options.format === "yaml") {
2096
- const output = YAML5.stringify({ generated: now, gaps });
2762
+ const output = YAML6.stringify({ generated: now, gaps });
2097
2763
  if (options.output) {
2098
2764
  writeFileSync4(options.output, output, "utf-8");
2099
2765
  printSuccess(`Report saved to: ${options.output}`);
@@ -2154,7 +2820,7 @@ async function generateCrosswalkReport(assetPath, options) {
2154
2820
  }
2155
2821
  let card;
2156
2822
  try {
2157
- card = loadAssetCard6(assetPath);
2823
+ card = loadAssetCard7(assetPath);
2158
2824
  } catch (error) {
2159
2825
  printError(error instanceof Error ? error.message : String(error));
2160
2826
  process.exit(1);
@@ -2193,7 +2859,7 @@ async function generateCrosswalkReport(assetPath, options) {
2193
2859
  return;
2194
2860
  }
2195
2861
  if (options.format === "yaml") {
2196
- const output = YAML5.stringify({
2862
+ const output = YAML6.stringify({
2197
2863
  generated: now,
2198
2864
  asset: { id: card.id, name: card.name },
2199
2865
  aigrcRiskLevel: card.classification.riskLevel,
@@ -2256,7 +2922,7 @@ async function generateCrosswalkReport(assetPath, options) {
2256
2922
  async function generateAuditPackage(options) {
2257
2923
  printHeader();
2258
2924
  printSubheader("Generating Audit Package");
2259
- const spinner = ora8("Collecting assets...").start();
2925
+ const spinner = ora9("Collecting assets...").start();
2260
2926
  let cardPaths = [];
2261
2927
  if (options.includeAssets && options.includeAssets.length > 0) {
2262
2928
  cardPaths = options.includeAssets;
@@ -2271,9 +2937,9 @@ async function generateAuditPackage(options) {
2271
2937
  process.exit(1);
2272
2938
  }
2273
2939
  const cards = [];
2274
- for (const path6 of cardPaths) {
2940
+ for (const path9 of cardPaths) {
2275
2941
  try {
2276
- cards.push(loadAssetCard6(path6));
2942
+ cards.push(loadAssetCard7(path9));
2277
2943
  } catch {
2278
2944
  }
2279
2945
  }
@@ -2311,7 +2977,7 @@ ${cards.map((c) => `| ${c.name} | ${c.classification.riskLevel} | ${c.governance
2311
2977
  mkdirSync2(assetsDir, { recursive: true });
2312
2978
  for (const card of cards) {
2313
2979
  const filename = `${card.id}.yaml`;
2314
- writeFileSync4(join5(assetsDir, filename), YAML5.stringify(card, { indent: 2 }), "utf-8");
2980
+ writeFileSync4(join5(assetsDir, filename), YAML6.stringify(card, { indent: 2 }), "utf-8");
2315
2981
  }
2316
2982
  const inventory = {
2317
2983
  generated: now,
@@ -2335,7 +3001,7 @@ ${cards.map((c) => `| ${c.name} | ${c.classification.riskLevel} | ${c.governance
2335
3001
  status: c.governance.status
2336
3002
  }))
2337
3003
  };
2338
- writeFileSync4(join5(outputDir, "inventory.yaml"), YAML5.stringify(inventory, { indent: 2 }), "utf-8");
3004
+ writeFileSync4(join5(outputDir, "inventory.yaml"), YAML6.stringify(inventory, { indent: 2 }), "utf-8");
2339
3005
  console.log();
2340
3006
  printSuccess(`Audit package created: ${outputDir}`);
2341
3007
  printInfo(` - README.md (Executive Summary)`);
@@ -2349,7 +3015,7 @@ function loadActiveProfiles5() {
2349
3015
  }
2350
3016
  try {
2351
3017
  const content = readFileSync5(configPath, "utf-8");
2352
- const config = YAML5.parse(content);
3018
+ const config = YAML6.parse(content);
2353
3019
  return config?.profiles || ["eu-ai-act"];
2354
3020
  } catch {
2355
3021
  return ["eu-ai-act"];
@@ -2363,6 +3029,8 @@ program.addCommand(initCommand);
2363
3029
  program.addCommand(registerCommand);
2364
3030
  program.addCommand(validateCommand);
2365
3031
  program.addCommand(statusCommand);
3032
+ program.addCommand(hashCommand);
3033
+ program.addCommand(versionCommand);
2366
3034
  program.addCommand(complianceCommand);
2367
3035
  program.addCommand(classifyCommand);
2368
3036
  program.addCommand(checkCommand);