@fulmenhq/tsfulmen 0.3.0 → 0.3.2

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.
Files changed (42) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/config/crucible-ts/repository/app-identity/app-identity.example.yaml +8 -0
  3. package/config/crucible-ts/repository/app-identity/fixtures/valid/typescript-package.yaml +17 -0
  4. package/config/crucible-ts/repository/app-identity/parity-snapshot.json +28 -0
  5. package/config/crucible-ts/taxonomy/metrics.yaml +1 -1
  6. package/dist/appidentity/index.js +156 -4150
  7. package/dist/appidentity/index.js.map +1 -1
  8. package/dist/bin/prometheus-cli.d.ts +1 -0
  9. package/dist/bin/prometheus-cli.js +9331 -0
  10. package/dist/bin/prometheus-cli.js.map +1 -0
  11. package/dist/bin/schema-cli.d.ts +1 -0
  12. package/dist/bin/schema-cli.js +6104 -0
  13. package/dist/bin/schema-cli.js.map +1 -0
  14. package/dist/bin/signals-cli.d.ts +1 -0
  15. package/dist/bin/signals-cli.js +2104 -0
  16. package/dist/bin/signals-cli.js.map +1 -0
  17. package/dist/config/index.js +29 -4915
  18. package/dist/config/index.js.map +1 -1
  19. package/dist/crucible/index.js +120 -5336
  20. package/dist/crucible/index.js.map +1 -1
  21. package/dist/errors/index.js +52 -4434
  22. package/dist/errors/index.js.map +1 -1
  23. package/dist/foundry/index.js +197 -1874
  24. package/dist/foundry/index.js.map +1 -1
  25. package/dist/index.d.ts +1 -1
  26. package/dist/index.js +161 -4154
  27. package/dist/index.js.map +1 -1
  28. package/dist/pathfinder/index.js +47 -4378
  29. package/dist/pathfinder/index.js.map +1 -1
  30. package/dist/reports/license-inventory.csv +2 -2
  31. package/dist/schema/index.js +0 -4
  32. package/dist/schema/index.js.map +1 -1
  33. package/dist/signals/index.js +231 -3570
  34. package/dist/signals/index.js.map +1 -1
  35. package/dist/telemetry/http/index.js +94 -5280
  36. package/dist/telemetry/http/index.js.map +1 -1
  37. package/dist/telemetry/index.js +70 -4786
  38. package/dist/telemetry/index.js.map +1 -1
  39. package/dist/telemetry/prometheus/index.js +461 -4450
  40. package/dist/telemetry/prometheus/index.js.map +1 -1
  41. package/package.json +8 -2
  42. package/schemas/crucible-ts/config/repository/app-identity/v1.0.0/app-identity.schema.json +34 -0
@@ -1,29 +1,20 @@
1
- import { access, readFile, mkdir, writeFile } from 'fs/promises';
2
- import { dirname, extname, join, relative } from 'path';
3
- import { parse, stringify } from 'yaml';
1
+ import { readFile, access } from 'fs/promises';
2
+ import { dirname, join, relative, extname } from 'path';
3
+ import { parse } from 'yaml';
4
4
  import addFormats from 'ajv-formats';
5
- import { spawn } from 'child_process';
5
+ import 'child_process';
6
6
  import { fileURLToPath } from 'url';
7
7
  import glob from 'fast-glob';
8
- import { Readable } from 'stream';
9
- import picomatch from 'picomatch';
10
- import { suggest as suggest$1, substringSimilarity, score as score$1, normalize as normalize$1, jaro_winkler, damerau_levenshtein, osa_distance, levenshtein } from '@3leaps/string-metrics-wasm';
11
- import 'crypto';
12
- import { Command } from 'commander';
8
+ import 'commander';
13
9
  import Ajv from 'ajv';
14
10
  import Ajv2019 from 'ajv/dist/2019.js';
15
11
  import Ajv2020 from 'ajv/dist/2020.js';
16
12
  import AjvDraft04 from 'ajv-draft-04';
17
13
 
18
- var __defProp = Object.defineProperty;
19
14
  var __getOwnPropNames = Object.getOwnPropertyNames;
20
15
  var __esm = (fn, res) => function __init() {
21
16
  return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
22
17
  };
23
- var __export = (target, all) => {
24
- for (var name in all)
25
- __defProp(target, name, { get: all[name], enumerable: true });
26
- };
27
18
 
28
19
  // src/telemetry/counter.ts
29
20
  var Counter;
@@ -752,23 +743,9 @@ var init_ajv_formats = __esm({
752
743
  });
753
744
 
754
745
  // src/schema/errors.ts
755
- var errors_exports = {};
756
- __export(errors_exports, {
757
- ExportErrorReason: () => ExportErrorReason,
758
- SchemaExportError: () => SchemaExportError,
759
- SchemaValidationError: () => SchemaValidationError
760
- });
761
- var ExportErrorReason, SchemaValidationError, SchemaExportError;
746
+ var SchemaValidationError;
762
747
  var init_errors = __esm({
763
748
  "src/schema/errors.ts"() {
764
- ExportErrorReason = /* @__PURE__ */ ((ExportErrorReason2) => {
765
- ExportErrorReason2["FILE_EXISTS"] = "FILE_EXISTS";
766
- ExportErrorReason2["WRITE_FAILED"] = "WRITE_FAILED";
767
- ExportErrorReason2["INVALID_FORMAT"] = "INVALID_FORMAT";
768
- ExportErrorReason2["PROVENANCE_FAILED"] = "PROVENANCE_FAILED";
769
- ExportErrorReason2["UNKNOWN"] = "UNKNOWN";
770
- return ExportErrorReason2;
771
- })(ExportErrorReason || {});
772
749
  SchemaValidationError = class _SchemaValidationError extends Error {
773
750
  constructor(message, schemaId, diagnostics = [], source, cause) {
774
751
  super(message);
@@ -908,100 +885,10 @@ Source: ${this.source.type}`;
908
885
  };
909
886
  }
910
887
  };
911
- SchemaExportError = class _SchemaExportError extends SchemaValidationError {
912
- constructor(message, reason, schemaId, outPath, cause) {
913
- super(message, schemaId, [], void 0, cause);
914
- this.reason = reason;
915
- this.schemaId = schemaId;
916
- this.outPath = outPath;
917
- this.cause = cause;
918
- this.name = "SchemaExportError";
919
- if (Error.captureStackTrace) {
920
- Error.captureStackTrace(this, _SchemaExportError);
921
- }
922
- }
923
- /**
924
- * Create error for file already exists
925
- */
926
- static fileExists(outPath) {
927
- return new _SchemaExportError(
928
- `Output file already exists: ${outPath}. Use overwrite option to replace.`,
929
- "FILE_EXISTS" /* FILE_EXISTS */,
930
- void 0,
931
- outPath
932
- );
933
- }
934
- /**
935
- * Create error for invalid export format
936
- */
937
- static invalidFormat(format, outPath) {
938
- return new _SchemaExportError(
939
- `Invalid export format: ${format}. Must be 'json' or 'yaml'.`,
940
- "INVALID_FORMAT" /* INVALID_FORMAT */,
941
- void 0,
942
- outPath
943
- );
944
- }
945
- /**
946
- * Create error for write failure
947
- */
948
- static writeFailed(outPath, error) {
949
- return new _SchemaExportError(
950
- `Failed to write schema to ${outPath}: ${error.message}`,
951
- "WRITE_FAILED" /* WRITE_FAILED */,
952
- void 0,
953
- outPath,
954
- error
955
- );
956
- }
957
- /**
958
- * Create error for provenance extraction failure
959
- */
960
- static provenanceFailed(details, error) {
961
- return new _SchemaExportError(
962
- `Failed to extract provenance metadata: ${details}`,
963
- "PROVENANCE_FAILED" /* PROVENANCE_FAILED */,
964
- void 0,
965
- void 0,
966
- error
967
- );
968
- }
969
- };
970
888
  }
971
889
  });
972
890
 
973
891
  // src/schema/utils.ts
974
- function formatDiagnostics(diagnostics) {
975
- if (diagnostics.length === 0) {
976
- return "No validation issues found.";
977
- }
978
- const lines = [];
979
- const errors = diagnostics.filter((d) => d.severity === "ERROR");
980
- const warnings = diagnostics.filter((d) => d.severity === "WARN");
981
- if (errors.length > 0) {
982
- lines.push(`\u274C ${errors.length} error(s) found:`);
983
- errors.forEach((diag, index) => {
984
- lines.push(` ${index + 1}. ${diag.message}`);
985
- if (diag.pointer) {
986
- lines.push(` at ${diag.pointer}`);
987
- }
988
- if (diag.keyword) {
989
- lines.push(` keyword: ${diag.keyword}`);
990
- }
991
- });
992
- }
993
- if (warnings.length > 0) {
994
- lines.push("");
995
- lines.push(`\u26A0\uFE0F ${warnings.length} warning(s) found:`);
996
- warnings.forEach((diag, index) => {
997
- lines.push(` ${index + 1}. ${diag.message}`);
998
- if (diag.pointer) {
999
- lines.push(` at ${diag.pointer}`);
1000
- }
1001
- });
1002
- }
1003
- return lines.join("\n");
1004
- }
1005
892
  function createDiagnostic(pointer, message, keyword, severity = "ERROR", source = "ajv", data) {
1006
893
  return {
1007
894
  pointer,
@@ -1017,261 +904,27 @@ var init_utils = __esm({
1017
904
  init_errors();
1018
905
  }
1019
906
  });
1020
- async function detectGoneat(customPath) {
1021
- if (customPath) {
1022
- try {
1023
- await access(customPath);
1024
- return customPath;
1025
- } catch {
1026
- return null;
1027
- }
1028
- }
1029
- if (process.env.GONEAT_PATH) {
1030
- try {
1031
- await access(process.env.GONEAT_PATH);
1032
- return process.env.GONEAT_PATH;
1033
- } catch {
1034
- }
1035
- }
1036
- try {
1037
- await access("./bin/goneat");
1038
- return "./bin/goneat";
1039
- } catch {
1040
- }
1041
- return "goneat";
1042
- }
1043
- async function isGoneatAvailable(goneatPath) {
1044
- let pathToTest;
1045
- if (goneatPath) {
1046
- pathToTest = goneatPath;
1047
- } else {
1048
- pathToTest = await detectGoneat();
1049
- if (!pathToTest) return false;
1050
- }
1051
- return new Promise((resolve) => {
1052
- const proc = spawn(pathToTest, ["version"], { stdio: "ignore" });
1053
- const timeout = setTimeout(() => {
1054
- proc.kill();
1055
- resolve(false);
1056
- }, 5e3);
1057
- proc.on("close", (code) => {
1058
- clearTimeout(timeout);
1059
- resolve(code === 0);
1060
- });
1061
- proc.on("error", () => {
1062
- clearTimeout(timeout);
1063
- resolve(false);
1064
- });
1065
- });
1066
- }
1067
- async function runGoneatValidation(schemaPath, dataPath, goneatPath) {
1068
- const detected = await detectGoneat(goneatPath);
1069
- if (!detected) {
1070
- return {
1071
- valid: false,
1072
- diagnostics: [
1073
- createDiagnostic(
1074
- "",
1075
- "goneat binary not found. Install goneat or specify path with --goneat-path",
1076
- "goneat-unavailable",
1077
- "ERROR",
1078
- "goneat"
1079
- )
1080
- ],
1081
- source: "goneat"
1082
- };
1083
- }
1084
- if (!await isGoneatAvailable(detected)) {
1085
- return {
1086
- valid: false,
1087
- diagnostics: [
1088
- createDiagnostic(
1089
- "",
1090
- `goneat binary found at '${detected}' but not executable or version check failed`,
1091
- "goneat-not-executable",
1092
- "ERROR",
1093
- "goneat"
1094
- )
1095
- ],
1096
- source: "goneat"
1097
- };
1098
- }
1099
- return new Promise((resolve) => {
1100
- const args = [
1101
- "schema",
1102
- "validate",
1103
- "--schema",
1104
- schemaPath,
1105
- "--data",
1106
- dataPath,
1107
- "--format",
1108
- "json"
1109
- ];
1110
- const proc = spawn(detected, args);
1111
- let stdout = "";
1112
- let stderr = "";
1113
- proc.stdout.on("data", (data) => {
1114
- stdout += data.toString();
1115
- });
1116
- proc.stderr.on("data", (data) => {
1117
- stderr += data.toString();
1118
- });
1119
- proc.on("close", (code) => {
1120
- let output;
1121
- try {
1122
- output = JSON.parse(stdout);
1123
- } catch {
1124
- resolve({
1125
- valid: false,
1126
- diagnostics: [
1127
- createDiagnostic(
1128
- "",
1129
- `goneat validation failed: ${stderr || "unknown error"}`,
1130
- "goneat-error",
1131
- "ERROR",
1132
- "goneat"
1133
- )
1134
- ],
1135
- source: "goneat"
1136
- });
1137
- return;
1138
- }
1139
- const diagnostics = output.errors?.map(
1140
- (error) => createDiagnostic(
1141
- error.path || "",
1142
- error.message,
1143
- error.keyword || "validation",
1144
- "ERROR",
1145
- "goneat"
1146
- )
1147
- ) || [];
1148
- resolve({
1149
- valid: code === 0 && output.valid,
1150
- diagnostics,
1151
- source: "goneat"
1152
- });
1153
- });
1154
- proc.on("error", (error) => {
1155
- resolve({
1156
- valid: false,
1157
- diagnostics: [
1158
- createDiagnostic(
1159
- "",
1160
- `Failed to execute goneat: ${error.message}`,
1161
- "goneat-spawn-error",
1162
- "ERROR",
1163
- "goneat"
1164
- )
1165
- ],
1166
- source: "goneat"
1167
- });
1168
- });
1169
- });
1170
- }
1171
907
  var init_goneat_bridge = __esm({
1172
908
  "src/schema/goneat-bridge.ts"() {
1173
909
  init_utils();
1174
910
  }
1175
911
  });
1176
- function parseSchemaInput(input) {
1177
- if (!input) {
1178
- throw SchemaValidationError.parseFailed(
1179
- { type: "string", content: "" },
1180
- new Error("schema content is empty")
1181
- );
1182
- }
1183
- try {
1184
- if (typeof input === "string") {
1185
- try {
1186
- return JSON.parse(input);
1187
- } catch {
1188
- return parse(input);
1189
- }
1190
- }
1191
- if (Buffer.isBuffer(input)) {
1192
- const content = input.toString("utf-8");
1193
- try {
1194
- return JSON.parse(content);
1195
- } catch {
1196
- return parse(content);
1197
- }
1198
- }
1199
- return input;
1200
- } catch (error) {
1201
- throw SchemaValidationError.parseFailed(
1202
- {
1203
- type: typeof input === "string" ? "string" : "object",
1204
- content: typeof input === "string" ? input : JSON.stringify(input)
1205
- },
1206
- error
1207
- );
1208
- }
1209
- }
1210
- function sortObjectKeys(obj) {
1211
- if (obj === null || typeof obj !== "object") {
1212
- return obj;
1213
- }
1214
- if (Array.isArray(obj)) {
1215
- return obj.map(sortObjectKeys);
1216
- }
1217
- const sorted = {};
1218
- const keys = Object.keys(obj).sort();
1219
- for (const key of keys) {
1220
- sorted[key] = sortObjectKeys(obj[key]);
1221
- }
1222
- return sorted;
1223
- }
1224
- function normalizeSchema(input, options = {}) {
1225
- try {
1226
- const parsed = parseSchemaInput(input);
1227
- const sorted = sortObjectKeys(parsed);
1228
- if (options.compact) {
1229
- return JSON.stringify(sorted);
1230
- }
1231
- return JSON.stringify(sorted, null, 2);
1232
- } catch (error) {
1233
- if (error instanceof SchemaValidationError) {
1234
- throw error;
1235
- }
1236
- throw SchemaValidationError.parseFailed(
1237
- {
1238
- type: typeof input === "string" ? "string" : "object",
1239
- content: typeof input === "string" ? input : JSON.stringify(input)
1240
- },
1241
- error
1242
- );
1243
- }
1244
- }
1245
- function compareSchemas(schemaA, schemaB, options = {}) {
1246
- const normalizedA = normalizeSchema(schemaA, options);
1247
- const normalizedB = normalizeSchema(schemaB, options);
1248
- return {
1249
- equal: normalizedA === normalizedB,
1250
- normalizedA,
1251
- normalizedB
1252
- };
1253
- }
1254
912
  var init_normalizer = __esm({
1255
913
  "src/schema/normalizer.ts"() {
1256
914
  init_errors();
1257
915
  }
1258
916
  });
1259
917
  function optionsChanged(newOptions) {
1260
- if (!newOptions && !globalRegistryOptions) return false;
1261
- if (!newOptions || !globalRegistryOptions) return true;
1262
- return newOptions.baseDir !== globalRegistryOptions.baseDir || JSON.stringify(newOptions.patterns) !== JSON.stringify(globalRegistryOptions.patterns) || newOptions.followSymlinks !== globalRegistryOptions.followSymlinks || newOptions.maxDepth !== globalRegistryOptions.maxDepth;
918
+ if (!globalRegistryOptions) return false;
919
+ return true;
1263
920
  }
1264
921
  function getSchemaRegistry(options) {
1265
- if (!globalRegistry || optionsChanged(options)) {
922
+ if (!globalRegistry || optionsChanged()) {
1266
923
  globalRegistry = new SchemaRegistry(options);
1267
924
  globalRegistryOptions = options;
1268
925
  }
1269
926
  return globalRegistry;
1270
927
  }
1271
- async function listSchemas(prefix, options) {
1272
- const registry = getSchemaRegistry(options);
1273
- return registry.listSchemas(prefix);
1274
- }
1275
928
  var DEFAULT_PATTERNS, SchemaRegistry, globalRegistry, globalRegistryOptions;
1276
929
  var init_registry2 = __esm({
1277
930
  "src/schema/registry.ts"() {
@@ -1292,9 +945,9 @@ var init_registry2 = __esm({
1292
945
  * Get default schema directory using import.meta.url
1293
946
  */
1294
947
  getDefaultSchemaDir() {
1295
- const __filename3 = fileURLToPath(import.meta.url);
1296
- const __dirname4 = dirname(__filename3);
1297
- return join(__dirname4, "..", "..", "schemas", "crucible-ts");
948
+ const __filename2 = fileURLToPath(import.meta.url);
949
+ const __dirname3 = dirname(__filename2);
950
+ return join(__dirname3, "..", "..", "schemas", "crucible-ts");
1298
951
  }
1299
952
  /**
1300
953
  * Build logical schema ID from file path
@@ -1316,3056 +969,144 @@ var init_registry2 = __esm({
1316
969
  case ".yml":
1317
970
  return "yaml";
1318
971
  default:
1319
- return "json";
1320
- }
1321
- }
1322
- /**
1323
- * Extract metadata from schema file
1324
- */
1325
- async extractMetadata(filePath) {
1326
- try {
1327
- const content = await readFile(filePath, "utf-8");
1328
- const format = this.getSchemaFormat(filePath);
1329
- let parsed;
1330
- if (format === "yaml") {
1331
- parsed = parse(content);
1332
- } else {
1333
- parsed = JSON.parse(content);
1334
- }
1335
- const baseDir = this.options.baseDir ?? "";
1336
- const relativePath = relative(baseDir, filePath);
1337
- return {
1338
- id: this.buildSchemaId(filePath, baseDir),
1339
- path: filePath,
1340
- relativePath,
1341
- format,
1342
- version: parsed.$schema || parsed.version,
1343
- description: parsed.title || parsed.description,
1344
- schemaDraft: parsed.$schema
1345
- };
1346
- } catch (error) {
1347
- throw SchemaValidationError.registryError(
1348
- "metadata extraction",
1349
- `Failed to process ${filePath}: ${error.message}`
1350
- );
1351
- }
1352
- }
1353
- /**
1354
- * Discover and index all available schemas
1355
- */
1356
- async discoverSchemas() {
1357
- try {
1358
- const baseDir = this.options.baseDir ?? "";
1359
- const patterns = this.options.patterns ?? [];
1360
- if (patterns.length === 0) {
1361
- this.schemas.clear();
1362
- return;
1363
- }
1364
- const pattern = patterns.map((p) => join(baseDir, p));
1365
- try {
1366
- await access(baseDir);
1367
- } catch {
1368
- this.schemas.clear();
1369
- return;
1370
- }
1371
- const files = await glob(pattern, {
1372
- absolute: true,
1373
- followSymbolicLinks: this.options.followSymlinks,
1374
- deep: this.options.maxDepth,
1375
- onlyFiles: true,
1376
- suppressErrors: true
1377
- // Don't throw on permission errors
1378
- });
1379
- this.schemas.clear();
1380
- for (const filePath of files) {
1381
- try {
1382
- const metadata = await this.extractMetadata(filePath);
1383
- this.schemas.set(metadata.id, metadata);
1384
- } catch (error) {
1385
- console.warn(`Warning: Failed to process schema ${filePath}:`, error);
1386
- }
1387
- }
1388
- } catch (error) {
1389
- throw SchemaValidationError.registryError("discovery", error.message);
1390
- }
1391
- }
1392
- /**
1393
- * List available schemas with optional prefix filtering
1394
- */
1395
- async listSchemas(prefix) {
1396
- if (this.schemas.size === 0) {
1397
- await this.discoverSchemas();
1398
- }
1399
- const schemas = Array.from(this.schemas.values());
1400
- if (prefix) {
1401
- return schemas.filter((schema) => schema.id.startsWith(prefix));
1402
- }
1403
- return schemas;
1404
- }
1405
- /**
1406
- * Get schema by logical ID
1407
- */
1408
- async getSchema(id) {
1409
- if (this.schemas.size === 0) {
1410
- await this.discoverSchemas();
1411
- }
1412
- const schema = this.schemas.get(id);
1413
- if (!schema) {
1414
- throw SchemaValidationError.schemaNotFound(id);
1415
- }
1416
- return schema;
1417
- }
1418
- /**
1419
- * Get schema by file path
1420
- */
1421
- async getSchemaByPath(filePath) {
1422
- if (this.schemas.size === 0) {
1423
- await this.discoverSchemas();
1424
- }
1425
- const absolutePath = filePath.startsWith("/") ? filePath : join(process.cwd(), filePath);
1426
- for (const schema of this.schemas.values()) {
1427
- if (schema.path === absolutePath) {
1428
- return schema;
1429
- }
1430
- }
1431
- throw SchemaValidationError.schemaNotFound(filePath);
1432
- }
1433
- /**
1434
- * Check if schema exists
1435
- */
1436
- async hasSchema(id) {
1437
- if (this.schemas.size === 0) {
1438
- await this.discoverSchemas();
1439
- }
1440
- return this.schemas.has(id);
1441
- }
1442
- /**
1443
- * Get registry size
1444
- */
1445
- get size() {
1446
- return this.schemas.size;
1447
- }
1448
- /**
1449
- * Clear registry cache
1450
- */
1451
- clear() {
1452
- this.schemas.clear();
1453
- }
1454
- };
1455
- }
1456
- });
1457
-
1458
- // src/schema/export.ts
1459
- var export_exports = {};
1460
- __export(export_exports, {
1461
- exportSchema: () => exportSchema,
1462
- stripProvenance: () => stripProvenance
1463
- });
1464
- async function extractProvenanceMetadata(schemaId) {
1465
- try {
1466
- const __filename3 = fileURLToPath(import.meta.url);
1467
- const __dirname4 = dirname(__filename3);
1468
- const metadataPath = join(__dirname4, "..", "..", ".crucible", "metadata", "metadata.yaml");
1469
- const metadataContent = await readFile(metadataPath, "utf-8");
1470
- const metadata = parse(metadataContent);
1471
- const crucibleSource = metadata.sources?.[0];
1472
- const crucibleVersion = crucibleSource?.version || "unknown";
1473
- const revision = crucibleSource?.commit;
1474
- const pkgPath = join(__dirname4, "..", "..", "package.json");
1475
- const pkgContent = await readFile(pkgPath, "utf-8");
1476
- const pkg = JSON.parse(pkgContent);
1477
- return {
1478
- schema_id: schemaId,
1479
- crucible_version: crucibleVersion,
1480
- library_version: pkg.version,
1481
- revision,
1482
- exported_at: (/* @__PURE__ */ new Date()).toISOString(),
1483
- export_source: "tsfulmen"
1484
- };
1485
- } catch (error) {
1486
- throw SchemaExportError.provenanceFailed(error.message, error);
1487
- }
1488
- }
1489
- function embedProvenance(schemaContent, provenance, format) {
1490
- if (format === "json") {
1491
- const withProvenance = {
1492
- ...schemaContent,
1493
- $comment: {
1494
- ...typeof schemaContent.$comment === "object" ? schemaContent.$comment : {},
1495
- "x-crucible-source": provenance
1496
- }
1497
- };
1498
- return JSON.stringify(withProvenance, null, 2);
1499
- }
1500
- const yamlContent = stringify(schemaContent, {
1501
- indent: 2,
1502
- lineWidth: 0
1503
- });
1504
- const provenanceComment = [
1505
- "# x-crucible-source:",
1506
- `# schema_id: ${provenance.schema_id}`,
1507
- `# crucible_version: ${provenance.crucible_version}`,
1508
- `# library_version: ${provenance.library_version}`,
1509
- ...provenance.revision ? [`# revision: ${provenance.revision}`] : [],
1510
- `# exported_at: ${provenance.exported_at}`,
1511
- `# export_source: ${provenance.export_source}`,
1512
- ""
1513
- ].join("\n");
1514
- return provenanceComment + yamlContent;
1515
- }
1516
- function detectFormat(outPath, formatOption) {
1517
- if (formatOption && formatOption !== "auto") {
1518
- return formatOption;
1519
- }
1520
- const ext = extname(outPath).toLowerCase();
1521
- switch (ext) {
1522
- case ".json":
1523
- return "json";
1524
- case ".yaml":
1525
- case ".yml":
1526
- return "yaml";
1527
- default:
1528
- throw SchemaExportError.invalidFormat(ext, outPath);
1529
- }
1530
- }
1531
- async function exportSchema(options) {
1532
- const {
1533
- schemaId,
1534
- outPath,
1535
- includeProvenance = true,
1536
- validate = true,
1537
- overwrite = false,
1538
- format: formatOption,
1539
- baseDir
1540
- } = options;
1541
- const format = detectFormat(outPath, formatOption);
1542
- if (!overwrite) {
1543
- try {
1544
- await access(outPath);
1545
- throw SchemaExportError.fileExists(outPath);
1546
- } catch (error) {
1547
- if (error.code !== "ENOENT") {
1548
- throw error;
1549
- }
1550
- }
1551
- }
1552
- const registry = getSchemaRegistry({ baseDir });
1553
- const schema = await registry.getSchema(schemaId);
1554
- const schemaContent = await readFile(schema.path, "utf-8");
1555
- if (validate) {
1556
- const validationResult = await validateSchema(schemaContent);
1557
- if (!validationResult.valid) {
1558
- throw SchemaValidationError.validationFailed(schemaId, validationResult.diagnostics, {
1559
- type: "file",
1560
- id: schema.path
1561
- });
1562
- }
1563
- }
1564
- let schemaObject;
1565
- try {
1566
- schemaObject = JSON.parse(schemaContent);
1567
- } catch {
1568
- schemaObject = parse(schemaContent);
1569
- }
1570
- Object.freeze(schemaObject);
1571
- let provenance;
1572
- let outputContent;
1573
- if (includeProvenance) {
1574
- provenance = await extractProvenanceMetadata(schemaId);
1575
- outputContent = embedProvenance(schemaObject, provenance, format);
1576
- } else {
1577
- if (format === "json") {
1578
- outputContent = JSON.stringify(schemaObject, null, 2);
1579
- } else {
1580
- outputContent = stringify(schemaObject, { indent: 2, lineWidth: 0 });
1581
- }
1582
- }
1583
- await mkdir(dirname(outPath), { recursive: true });
1584
- try {
1585
- await writeFile(outPath, outputContent, "utf-8");
1586
- } catch (error) {
1587
- throw SchemaExportError.writeFailed(outPath, error);
1588
- }
1589
- return {
1590
- success: true,
1591
- schemaId,
1592
- outPath,
1593
- format,
1594
- includeProvenance,
1595
- provenance
1596
- };
1597
- }
1598
- function stripProvenance(content) {
1599
- try {
1600
- const parsed = JSON.parse(content);
1601
- if (parsed.$comment && typeof parsed.$comment === "object") {
1602
- const comment = { ...parsed.$comment };
1603
- delete comment["x-crucible-source"];
1604
- if (Object.keys(comment).length === 0) {
1605
- delete parsed.$comment;
1606
- } else {
1607
- parsed.$comment = comment;
1608
- }
1609
- }
1610
- return JSON.stringify(parsed, null, 2);
1611
- } catch {
1612
- const lines = content.split("\n");
1613
- const filtered = lines.filter((line) => {
1614
- const trimmed = line.trim();
1615
- return !(trimmed.startsWith("# x-crucible-source:") || trimmed.startsWith("# ") && /^#\s+(schema_id|crucible_version|library_version|revision|exported_at|export_source):/.test(
1616
- trimmed
1617
- ));
1618
- });
1619
- while (filtered.length > 0 && filtered[0]?.trim() === "") {
1620
- filtered.shift();
1621
- }
1622
- return filtered.join("\n");
1623
- }
1624
- }
1625
- var init_export = __esm({
1626
- "src/schema/export.ts"() {
1627
- init_errors();
1628
- init_registry2();
1629
- init_validator();
1630
- }
1631
- });
1632
-
1633
- // src/foundry/errors.ts
1634
- var FoundryCatalogError;
1635
- var init_errors2 = __esm({
1636
- "src/foundry/errors.ts"() {
1637
- FoundryCatalogError = class _FoundryCatalogError extends Error {
1638
- constructor(message, catalog, cause) {
1639
- super(message);
1640
- this.catalog = catalog;
1641
- this.cause = cause;
1642
- this.name = "FoundryCatalogError";
1643
- if (Error.captureStackTrace) {
1644
- Error.captureStackTrace(this, _FoundryCatalogError);
1645
- }
1646
- }
1647
- static invalidSchema(catalog, details, cause) {
1648
- return new _FoundryCatalogError(
1649
- `Invalid schema in ${catalog} catalog: ${details}`,
1650
- catalog,
1651
- cause
1652
- );
1653
- }
1654
- static missingCatalog(catalog) {
1655
- return new _FoundryCatalogError(`Catalog ${catalog} not found or could not be loaded`, catalog);
1656
- }
1657
- static invalidPattern(patternId, details) {
1658
- return new _FoundryCatalogError(`Invalid pattern ${patternId}: ${details}`, "patterns");
1659
- }
1660
- static compilationError(patternId, details, cause) {
1661
- return new _FoundryCatalogError(
1662
- `Failed to compile pattern ${patternId}: ${details}`,
1663
- "patterns",
1664
- cause
1665
- );
1666
- }
1667
- };
1668
- }
1669
- });
1670
- async function loadCatalog(filePath, catalogName, schemaId) {
1671
- try {
1672
- let content;
1673
- if (typeof Bun !== "undefined") {
1674
- try {
1675
- const file = Bun.file(filePath);
1676
- if (!await file.exists()) {
1677
- throw FoundryCatalogError.missingCatalog(catalogName);
1678
- }
1679
- content = await file.text();
1680
- } catch (error) {
1681
- if (error instanceof Error && error.message.includes("No such file")) {
1682
- throw FoundryCatalogError.missingCatalog(catalogName);
1683
- }
1684
- throw error;
1685
- }
1686
- } else {
1687
- try {
1688
- content = await readFile(filePath, "utf-8");
1689
- } catch (error) {
1690
- if (error.code === "ENOENT") {
1691
- throw FoundryCatalogError.missingCatalog(catalogName);
1692
- }
1693
- throw error;
1694
- }
1695
- }
1696
- const data = parse(content);
1697
- const result = await validateDataBySchemaId(data, schemaId);
1698
- if (!result.valid) {
1699
- const errorMessages = result.diagnostics.map((d) => `${d.pointer}: ${d.message}`).join("; ");
1700
- throw FoundryCatalogError.invalidSchema(
1701
- catalogName,
1702
- `Schema validation failed: ${errorMessages}`
1703
- );
1704
- }
1705
- return data;
1706
- } catch (error) {
1707
- if (error instanceof FoundryCatalogError) {
1708
- throw error;
1709
- }
1710
- const err = error;
1711
- if (err.code === "ENOENT") {
1712
- throw FoundryCatalogError.missingCatalog(catalogName);
1713
- } else if (err.code === "EACCES") {
1714
- throw FoundryCatalogError.invalidSchema(
1715
- catalogName,
1716
- "Permission denied accessing catalog file",
1717
- err
1718
- );
1719
- } else if (err.code === "EISDIR") {
1720
- throw FoundryCatalogError.invalidSchema(
1721
- catalogName,
1722
- "Expected file but found directory",
1723
- err
1724
- );
1725
- } else if (err.code === "EMFILE" || err.code === "ENFILE") {
1726
- throw FoundryCatalogError.invalidSchema(catalogName, "Too many open files", err);
1727
- }
1728
- throw FoundryCatalogError.invalidSchema(catalogName, "Failed to load catalog", err);
1729
- }
1730
- }
1731
- async function loadPatternCatalog() {
1732
- return loadCatalog(SSOT_PATHS.patterns, "patterns", SCHEMA_IDS.patterns);
1733
- }
1734
- async function loadHttpStatusCatalog() {
1735
- return loadCatalog(
1736
- SSOT_PATHS.httpStatuses,
1737
- "httpStatuses",
1738
- SCHEMA_IDS.httpStatuses
1739
- );
1740
- }
1741
- async function loadMimeTypeCatalog() {
1742
- return loadCatalog(SSOT_PATHS.mimeTypes, "mimeTypes", SCHEMA_IDS.mimeTypes);
1743
- }
1744
- async function loadCountryCodeCatalog() {
1745
- return loadCatalog(
1746
- SSOT_PATHS.countryCodes,
1747
- "countryCodes",
1748
- SCHEMA_IDS.countryCodes
1749
- );
1750
- }
1751
- async function loadAllCatalogs() {
1752
- const [patterns, httpStatuses, mimeTypes, countryCodes] = await Promise.all([
1753
- loadPatternCatalog(),
1754
- loadHttpStatusCatalog(),
1755
- loadMimeTypeCatalog(),
1756
- loadCountryCodeCatalog()
1757
- ]);
1758
- return { patterns, httpStatuses, mimeTypes, countryCodes };
1759
- }
1760
- var __filename, __dirname2, SSOT_PATHS, SCHEMA_IDS;
1761
- var init_loader = __esm({
1762
- "src/foundry/loader.ts"() {
1763
- init_validator();
1764
- init_errors2();
1765
- __filename = fileURLToPath(import.meta.url);
1766
- __dirname2 = dirname(__filename);
1767
- SSOT_PATHS = {
1768
- patterns: join(__dirname2, "../../config/crucible-ts/library/foundry/patterns.yaml"),
1769
- httpStatuses: join(__dirname2, "../../config/crucible-ts/library/foundry/http-statuses.yaml"),
1770
- mimeTypes: join(__dirname2, "../../config/crucible-ts/library/foundry/mime-types.yaml"),
1771
- countryCodes: join(__dirname2, "../../config/crucible-ts/library/foundry/country-codes.yaml")
1772
- };
1773
- SCHEMA_IDS = {
1774
- patterns: "library/foundry/v1.0.0/patterns",
1775
- httpStatuses: "library/foundry/v1.0.0/http-status-groups",
1776
- mimeTypes: "library/foundry/v1.0.0/mime-types",
1777
- countryCodes: "library/foundry/v1.0.0/country-codes"
1778
- };
1779
- }
1780
- });
1781
-
1782
- // src/foundry/country-codes.ts
1783
- function deepClone(obj) {
1784
- if (obj === null || typeof obj !== "object") {
1785
- return obj;
1786
- }
1787
- if (Array.isArray(obj)) {
1788
- return obj.map((item) => deepClone(item));
1789
- }
1790
- const cloned = {};
1791
- for (const key in obj) {
1792
- if (Object.hasOwn(obj, key)) {
1793
- cloned[key] = deepClone(obj[key]);
1794
- }
1795
- }
1796
- return cloned;
1797
- }
1798
- function deepFreeze(obj) {
1799
- Object.freeze(obj);
1800
- for (const key in obj) {
1801
- if (Object.hasOwn(obj, key)) {
1802
- const value = obj[key];
1803
- if (value !== null && typeof value === "object") {
1804
- deepFreeze(value);
1805
- }
1806
- }
1807
- }
1808
- return obj;
1809
- }
1810
- function normalizeNumeric(code) {
1811
- const str = typeof code === "number" ? code.toString() : code;
1812
- return str.padStart(3, "0");
1813
- }
1814
- async function ensureCatalogLoaded() {
1815
- if (catalogCache !== null) {
1816
- return;
1817
- }
1818
- catalogCache = await loadCountryCodeCatalog();
1819
- for (const country of catalogCache.countries) {
1820
- alpha2Index.set(country.alpha2.toUpperCase(), country);
1821
- alpha3Index.set(country.alpha3.toUpperCase(), country);
1822
- const normalized = normalizeNumeric(country.numeric);
1823
- numericIndex.set(normalized, country);
1824
- }
1825
- }
1826
- async function getCountryByAlpha2(code) {
1827
- await ensureCatalogLoaded();
1828
- const normalized = code.toUpperCase();
1829
- const country = alpha2Index.get(normalized);
1830
- return country ? deepFreeze(deepClone(country)) : null;
1831
- }
1832
- async function getCountryByAlpha3(code) {
1833
- await ensureCatalogLoaded();
1834
- const normalized = code.toUpperCase();
1835
- const country = alpha3Index.get(normalized);
1836
- return country ? deepFreeze(deepClone(country)) : null;
1837
- }
1838
- async function getCountryByNumeric(code) {
1839
- await ensureCatalogLoaded();
1840
- const normalized = normalizeNumeric(code);
1841
- const country = numericIndex.get(normalized);
1842
- return country ? deepFreeze(deepClone(country)) : null;
1843
- }
1844
- async function listCountries() {
1845
- await ensureCatalogLoaded();
1846
- return Array.from(alpha2Index.values()).map((c) => deepFreeze(deepClone(c)));
1847
- }
1848
- function clearCountryCodeCache() {
1849
- catalogCache = null;
1850
- alpha2Index.clear();
1851
- alpha3Index.clear();
1852
- numericIndex.clear();
1853
- }
1854
- var catalogCache, alpha2Index, alpha3Index, numericIndex;
1855
- var init_country_codes = __esm({
1856
- "src/foundry/country-codes.ts"() {
1857
- init_loader();
1858
- catalogCache = null;
1859
- alpha2Index = /* @__PURE__ */ new Map();
1860
- alpha3Index = /* @__PURE__ */ new Map();
1861
- numericIndex = /* @__PURE__ */ new Map();
1862
- }
1863
- });
1864
-
1865
- // src/crucible/foundry/exitCodes.ts
1866
- function getExitCodeInfo(code) {
1867
- return exitCodeMetadata[code];
1868
- }
1869
- var exitCodes, exitCodeMetadata, EXIT_CODES_VERSION;
1870
- var init_exitCodes = __esm({
1871
- "src/crucible/foundry/exitCodes.ts"() {
1872
- exitCodes = {
1873
- // Standard Exit Codes (0-1)
1874
- // POSIX standard success and generic failure codes
1875
- EXIT_SUCCESS: 0,
1876
- EXIT_FAILURE: 1,
1877
- // Networking & Port Management (10-19)
1878
- // Network-related failures (ports, connectivity, etc.)
1879
- EXIT_PORT_IN_USE: 10,
1880
- EXIT_PORT_RANGE_EXHAUSTED: 11,
1881
- EXIT_INSTANCE_ALREADY_RUNNING: 12,
1882
- EXIT_NETWORK_UNREACHABLE: 13,
1883
- EXIT_CONNECTION_REFUSED: 14,
1884
- EXIT_CONNECTION_TIMEOUT: 15,
1885
- // Configuration & Validation (20-29)
1886
- // Configuration errors, validation failures, version mismatches
1887
- EXIT_CONFIG_INVALID: 20,
1888
- EXIT_MISSING_DEPENDENCY: 21,
1889
- EXIT_SSOT_VERSION_MISMATCH: 22,
1890
- EXIT_CONFIG_FILE_NOT_FOUND: 23,
1891
- EXIT_ENVIRONMENT_INVALID: 24,
1892
- // Runtime Errors (30-39)
1893
- // Errors during normal operation (health checks, database, etc.)
1894
- EXIT_HEALTH_CHECK_FAILED: 30,
1895
- EXIT_DATABASE_UNAVAILABLE: 31,
1896
- EXIT_EXTERNAL_SERVICE_UNAVAILABLE: 32,
1897
- EXIT_RESOURCE_EXHAUSTED: 33,
1898
- EXIT_OPERATION_TIMEOUT: 34,
1899
- // Command-Line Usage Errors (40-49)
1900
- // Invalid arguments, missing required flags, usage errors
1901
- EXIT_INVALID_ARGUMENT: 40,
1902
- EXIT_MISSING_REQUIRED_ARGUMENT: 41,
1903
- EXIT_USAGE: 64,
1904
- // Permissions & File Access (50-59)
1905
- // Permission denied, file not found, access errors
1906
- EXIT_PERMISSION_DENIED: 50,
1907
- EXIT_FILE_NOT_FOUND: 51,
1908
- EXIT_DIRECTORY_NOT_FOUND: 52,
1909
- EXIT_FILE_READ_ERROR: 53,
1910
- EXIT_FILE_WRITE_ERROR: 54,
1911
- // Data & Processing Errors (60-69)
1912
- // Data validation, parsing, transformation failures
1913
- EXIT_DATA_INVALID: 60,
1914
- EXIT_PARSE_ERROR: 61,
1915
- EXIT_TRANSFORMATION_FAILED: 62,
1916
- EXIT_DATA_CORRUPT: 63,
1917
- // Security & Authentication (70-79)
1918
- // Authentication failures, authorization errors, security violations
1919
- EXIT_AUTHENTICATION_FAILED: 70,
1920
- EXIT_AUTHORIZATION_FAILED: 71,
1921
- EXIT_SECURITY_VIOLATION: 72,
1922
- EXIT_CERTIFICATE_INVALID: 73,
1923
- // Observability & Monitoring (80-89)
1924
- // Observability infrastructure failures. Use when observability is CRITICAL to operation (e.g., monitoring agents, telemetry exporters). For workhorses where observability is auxiliary: - Log warning and continue (don't exit) - Emit degraded health status - Only exit if explicitly configured (fail_on_observability_error: true)
1925
- EXIT_METRICS_UNAVAILABLE: 80,
1926
- EXIT_TRACING_FAILED: 81,
1927
- EXIT_LOGGING_FAILED: 82,
1928
- EXIT_ALERT_SYSTEM_FAILED: 83,
1929
- EXIT_STRUCTURED_LOGGING_FAILED: 84,
1930
- // Testing & Validation (91-99)
1931
- // Test execution outcomes and validation failures. NOTE: Test harnesses MUST use EXIT_SUCCESS (0) for successful test runs per ecosystem conventions (pytest, Go testing, Jest all use 0 for success). Codes in this category are for FAILURES and exceptional conditions only.
1932
- EXIT_TEST_FAILURE: 91,
1933
- EXIT_TEST_ERROR: 92,
1934
- EXIT_TEST_INTERRUPTED: 93,
1935
- EXIT_TEST_USAGE_ERROR: 94,
1936
- EXIT_TEST_NO_TESTS_COLLECTED: 95,
1937
- EXIT_COVERAGE_THRESHOLD_NOT_MET: 96,
1938
- // Shell & Process Control (124-127)
1939
- // Exit codes from shell conventions and process control utilities (timeout, exec)
1940
- EXIT_TIMEOUT: 124,
1941
- EXIT_TIMEOUT_INTERNAL: 125,
1942
- EXIT_CANNOT_EXECUTE: 126,
1943
- EXIT_NOT_FOUND: 127,
1944
- // Signal-Induced Exits (128-165)
1945
- // Process terminated by Unix signals (128+N pattern per POSIX). Signal codes follow Linux numbering; macOS/FreeBSD differ for SIGUSR1/SIGUSR2. For full signal semantics, see config/library/foundry/signals.yaml. For signal handling patterns, see docs/standards/library/modules/signal-handling.md.
1946
- EXIT_SIGNAL_HUP: 129,
1947
- EXIT_SIGNAL_INT: 130,
1948
- EXIT_SIGNAL_QUIT: 131,
1949
- EXIT_SIGNAL_KILL: 137,
1950
- EXIT_SIGNAL_PIPE: 141,
1951
- EXIT_SIGNAL_ALRM: 142,
1952
- EXIT_SIGNAL_TERM: 143,
1953
- EXIT_SIGNAL_USR1: 138,
1954
- EXIT_SIGNAL_USR2: 140
1955
- };
1956
- exitCodeMetadata = {
1957
- 0: {
1958
- code: 0,
1959
- name: "EXIT_SUCCESS",
1960
- description: "Successful execution",
1961
- context: "Command completed without errors",
1962
- category: "standard"
1963
- },
1964
- 1: {
1965
- code: 1,
1966
- name: "EXIT_FAILURE",
1967
- description: "Generic failure (unspecified error)",
1968
- context: "Use when no more specific exit code applies",
1969
- category: "standard"
1970
- },
1971
- 10: {
1972
- code: 10,
1973
- name: "EXIT_PORT_IN_USE",
1974
- description: "Specified port is already in use",
1975
- context: "Server startup when port unavailable and fail_if_unavailable strategy",
1976
- category: "networking"
1977
- },
1978
- 11: {
1979
- code: 11,
1980
- name: "EXIT_PORT_RANGE_EXHAUSTED",
1981
- description: "No available ports in configured range",
1982
- context: "Server startup when all ports in environment range occupied",
1983
- category: "networking"
1984
- },
1985
- 12: {
1986
- code: 12,
1987
- name: "EXIT_INSTANCE_ALREADY_RUNNING",
1988
- description: "Another instance already running on target port",
1989
- context: "Server startup when PID registry shows active process on port",
1990
- category: "networking"
1991
- },
1992
- 13: {
1993
- code: 13,
1994
- name: "EXIT_NETWORK_UNREACHABLE",
1995
- description: "Network destination unreachable",
1996
- context: "Client connections, health checks, external service validation",
1997
- category: "networking"
1998
- },
1999
- 14: {
2000
- code: 14,
2001
- name: "EXIT_CONNECTION_REFUSED",
2002
- description: "Connection refused by remote host",
2003
- context: "Database connections, API endpoints, upstream services",
2004
- category: "networking"
2005
- },
2006
- 15: {
2007
- code: 15,
2008
- name: "EXIT_CONNECTION_TIMEOUT",
2009
- description: "Connection attempt timed out",
2010
- context: "Slow networks, unresponsive services, firewall blocks",
2011
- category: "networking"
2012
- },
2013
- 20: {
2014
- code: 20,
2015
- name: "EXIT_CONFIG_INVALID",
2016
- description: "Configuration file failed validation",
2017
- context: "Startup validation, schema mismatches, invalid YAML/JSON",
2018
- category: "configuration",
2019
- retryHint: "no_retry"
2020
- },
2021
- 21: {
2022
- code: 21,
2023
- name: "EXIT_MISSING_DEPENDENCY",
2024
- description: "Required dependency not found",
2025
- context: "Missing binaries, libraries, or runtime requirements",
2026
- category: "configuration",
2027
- retryHint: "investigate"
2028
- },
2029
- 22: {
2030
- code: 22,
2031
- name: "EXIT_SSOT_VERSION_MISMATCH",
2032
- description: "SSOT (Crucible) version incompatible",
2033
- context: "Helper library detects unsupported Crucible version",
2034
- category: "configuration",
2035
- retryHint: "no_retry"
2036
- },
2037
- 23: {
2038
- code: 23,
2039
- name: "EXIT_CONFIG_FILE_NOT_FOUND",
2040
- description: "Required configuration file not found",
2041
- context: "Explicitly specified config path doesn't exist",
2042
- category: "configuration"
2043
- },
2044
- 24: {
2045
- code: 24,
2046
- name: "EXIT_ENVIRONMENT_INVALID",
2047
- description: "Invalid or unsupported environment specification",
2048
- context: "Unknown environment name, missing environment config",
2049
- category: "configuration"
2050
- },
2051
- 30: {
2052
- code: 30,
2053
- name: "EXIT_HEALTH_CHECK_FAILED",
2054
- description: "Health check endpoint returned non-healthy status",
2055
- context: "Startup health validation, readiness probes",
2056
- category: "runtime",
2057
- retryHint: "retry"
2058
- },
2059
- 31: {
2060
- code: 31,
2061
- name: "EXIT_DATABASE_UNAVAILABLE",
2062
- description: "Database connection failed or unavailable",
2063
- context: "Startup connection checks, critical query failures",
2064
- category: "runtime",
2065
- retryHint: "retry"
2066
- },
2067
- 32: {
2068
- code: 32,
2069
- name: "EXIT_EXTERNAL_SERVICE_UNAVAILABLE",
2070
- description: "Required external service unavailable",
2071
- context: "API dependencies, message queues, cache servers",
2072
- category: "runtime"
2073
- },
2074
- 33: {
2075
- code: 33,
2076
- name: "EXIT_RESOURCE_EXHAUSTED",
2077
- description: "System resources exhausted (memory, disk, file descriptors)",
2078
- context: "Out-of-memory, disk full, too many open files",
2079
- category: "runtime",
2080
- retryHint: "investigate"
2081
- },
2082
- 34: {
2083
- code: 34,
2084
- name: "EXIT_OPERATION_TIMEOUT",
2085
- description: "Operation exceeded timeout threshold",
2086
- context: "Long-running tasks, async operations, batch processing",
2087
- category: "runtime",
2088
- retryHint: "retry"
2089
- },
2090
- 40: {
2091
- code: 40,
2092
- name: "EXIT_INVALID_ARGUMENT",
2093
- description: "Invalid command-line argument or flag value",
2094
- context: "Type errors, out-of-range values, malformed input",
2095
- category: "usage"
2096
- },
2097
- 41: {
2098
- code: 41,
2099
- name: "EXIT_MISSING_REQUIRED_ARGUMENT",
2100
- description: "Required command-line argument not provided",
2101
- context: "Missing --config, --port, or other required flags",
2102
- category: "usage"
2103
- },
2104
- 64: {
2105
- code: 64,
2106
- name: "EXIT_USAGE",
2107
- description: "Command-line usage error",
2108
- context: "BSD sysexits.h EX_USAGE - wrong number of arguments, bad syntax",
2109
- category: "usage",
2110
- bsdEquivalent: "EX_USAGE"
2111
- },
2112
- 50: {
2113
- code: 50,
2114
- name: "EXIT_PERMISSION_DENIED",
2115
- description: "Insufficient permissions for operation",
2116
- context: "File access, port binding (<1024), privileged operations",
2117
- category: "permissions"
2118
- },
2119
- 51: {
2120
- code: 51,
2121
- name: "EXIT_FILE_NOT_FOUND",
2122
- description: "Required file not found",
2123
- context: "Assets, templates, data files (not config - use 23)",
2124
- category: "permissions"
2125
- },
2126
- 52: {
2127
- code: 52,
2128
- name: "EXIT_DIRECTORY_NOT_FOUND",
2129
- description: "Required directory not found",
2130
- context: "State directories, log paths, data directories",
2131
- category: "permissions"
2132
- },
2133
- 53: {
2134
- code: 53,
2135
- name: "EXIT_FILE_READ_ERROR",
2136
- description: "Error reading file",
2137
- context: "Corrupt files, I/O errors, encoding issues",
2138
- category: "permissions"
2139
- },
2140
- 54: {
2141
- code: 54,
2142
- name: "EXIT_FILE_WRITE_ERROR",
2143
- description: "Error writing file",
2144
- context: "Disk full, read-only filesystem, permission errors",
2145
- category: "permissions"
2146
- },
2147
- 60: {
2148
- code: 60,
2149
- name: "EXIT_DATA_INVALID",
2150
- description: "Input data failed validation",
2151
- context: "Schema validation, business rule violations",
2152
- category: "data"
2153
- },
2154
- 61: {
2155
- code: 61,
2156
- name: "EXIT_PARSE_ERROR",
2157
- description: "Error parsing input data",
2158
- context: "Malformed JSON/YAML/XML, syntax errors",
2159
- category: "data"
2160
- },
2161
- 62: {
2162
- code: 62,
2163
- name: "EXIT_TRANSFORMATION_FAILED",
2164
- description: "Data transformation or conversion failed",
2165
- context: "Type conversions, format transformations, encoding changes",
2166
- category: "data"
2167
- },
2168
- 63: {
2169
- code: 63,
2170
- name: "EXIT_DATA_CORRUPT",
2171
- description: "Data corruption detected",
2172
- context: "Checksum failures, integrity violations",
2173
- category: "data"
2174
- },
2175
- 70: {
2176
- code: 70,
2177
- name: "EXIT_AUTHENTICATION_FAILED",
2178
- description: "Authentication failed",
2179
- context: "Invalid credentials, expired tokens, auth service unavailable",
2180
- category: "security"
2181
- },
2182
- 71: {
2183
- code: 71,
2184
- name: "EXIT_AUTHORIZATION_FAILED",
2185
- description: "Authorization failed (authenticated but insufficient permissions)",
2186
- context: "RBAC failures, scope violations, resource access denied",
2187
- category: "security"
2188
- },
2189
- 72: {
2190
- code: 72,
2191
- name: "EXIT_SECURITY_VIOLATION",
2192
- description: "Security policy violation detected",
2193
- context: "Suspicious activity, rate limit exceeded, IP blocklist",
2194
- category: "security"
2195
- },
2196
- 73: {
2197
- code: 73,
2198
- name: "EXIT_CERTIFICATE_INVALID",
2199
- description: "TLS/SSL certificate validation failed",
2200
- context: "Expired certs, untrusted CAs, hostname mismatches",
2201
- category: "security",
2202
- bsdEquivalent: "EX_PROTOCOL"
2203
- },
2204
- 80: {
2205
- code: 80,
2206
- name: "EXIT_METRICS_UNAVAILABLE",
2207
- description: "Metrics endpoint or collection system unavailable",
2208
- context: "Use for observability-focused tools (Prometheus exporters, StatsD agents).\nWorkhorses SHOULD log warning and continue unless configured to fail-fast.\n",
2209
- category: "observability"
2210
- },
2211
- 81: {
2212
- code: 81,
2213
- name: "EXIT_TRACING_FAILED",
2214
- description: "Distributed tracing system unavailable",
2215
- context: "OTLP exporter failed, Jaeger collector unreachable",
2216
- category: "observability"
2217
- },
2218
- 82: {
2219
- code: 82,
2220
- name: "EXIT_LOGGING_FAILED",
2221
- description: "Logging system unavailable or misconfigured",
2222
- context: "Log aggregator unreachable, log file unwritable",
2223
- category: "observability"
2224
- },
2225
- 83: {
2226
- code: 83,
2227
- name: "EXIT_ALERT_SYSTEM_FAILED",
2228
- description: "Alerting system unavailable",
2229
- context: "PagerDuty API failed, Slack webhook unreachable",
2230
- category: "observability"
2231
- },
2232
- 84: {
2233
- code: 84,
2234
- name: "EXIT_STRUCTURED_LOGGING_FAILED",
2235
- description: "Structured logging system unavailable",
2236
- context: "JSON log aggregator unreachable, log schema validation failed",
2237
- category: "observability"
2238
- },
2239
- 91: {
2240
- code: 91,
2241
- name: "EXIT_TEST_FAILURE",
2242
- description: "One or more tests failed",
2243
- context: "Test assertions failed, expected behavior not met.\nMaps to pytest exit code 1, Go test failure, Jest failure.\n",
2244
- category: "testing"
2245
- },
2246
- 92: {
2247
- code: 92,
2248
- name: "EXIT_TEST_ERROR",
2249
- description: "Test execution error (not test failure)",
2250
- context: "Test setup failed, fixture unavailable, test harness error.\nMaps to pytest exit code 3 (internal error).\n",
2251
- category: "testing"
2252
- },
2253
- 93: {
2254
- code: 93,
2255
- name: "EXIT_TEST_INTERRUPTED",
2256
- description: "Test run interrupted by user or system",
2257
- context: "Ctrl+C during tests, system signal, user cancellation.\nMaps to pytest exit code 2.\n",
2258
- category: "testing"
2259
- },
2260
- 94: {
2261
- code: 94,
2262
- name: "EXIT_TEST_USAGE_ERROR",
2263
- description: "Test command usage error",
2264
- context: "Invalid test arguments, bad configuration.\nMaps to pytest exit code 4.\n",
2265
- category: "testing"
2266
- },
2267
- 95: {
2268
- code: 95,
2269
- name: "EXIT_TEST_NO_TESTS_COLLECTED",
2270
- description: "No tests found or all tests skipped",
2271
- context: "Empty test suite, all tests deselected or skipped.\nMaps to pytest exit code 5.\n",
2272
- category: "testing"
2273
- },
2274
- 96: {
2275
- code: 96,
2276
- name: "EXIT_COVERAGE_THRESHOLD_NOT_MET",
2277
- description: "Test coverage below required threshold",
2278
- context: "Code coverage validation, quality gate failure",
2279
- category: "testing"
2280
- },
2281
- 124: {
2282
- code: 124,
2283
- name: "EXIT_TIMEOUT",
2284
- description: "Command timed out before completion",
2285
- context: "GNU timeout or similar utility terminated command after deadline",
2286
- category: "shell"
2287
- },
2288
- 125: {
2289
- code: 125,
2290
- name: "EXIT_TIMEOUT_INTERNAL",
2291
- description: "Timeout utility itself failed",
2292
- context: "Error in timeout tool before or during command execution (not command failure)",
2293
- category: "shell"
2294
- },
2295
- 126: {
2296
- code: 126,
2297
- name: "EXIT_CANNOT_EXECUTE",
2298
- description: "Command found but could not be executed",
2299
- context: "Permission denied, not executable, exec format error",
2300
- category: "shell",
2301
- bsdEquivalent: "EX_NOPERM (partial)"
2302
- },
2303
- 127: {
2304
- code: 127,
2305
- name: "EXIT_NOT_FOUND",
2306
- description: "Command not found",
2307
- context: "Executable not found in PATH or specified path does not exist",
2308
- category: "shell",
2309
- bsdEquivalent: "EX_UNAVAILABLE (partial)"
2310
- },
2311
- 129: {
2312
- code: 129,
2313
- name: "EXIT_SIGNAL_HUP",
2314
- description: "Hangup signal (SIGHUP) - config reload via restart",
2315
- context: "Config reload via restart-based pattern (mandatory schema validation).\nProcess exits with 129, supervisor restarts with new config.\nSee signals.yaml for reload behavior definition.",
2316
- category: "signals",
2317
- bsdEquivalent: "128 + 1"
2318
- },
2319
- 130: {
2320
- code: 130,
2321
- name: "EXIT_SIGNAL_INT",
2322
- description: "Interrupt signal (SIGINT) - user interrupt with Ctrl+C double-tap",
2323
- context: "Ctrl+C pressed. First tap initiates graceful shutdown, second within 2s forces immediate exit.\nSame exit code (130) for both graceful and force modes.\nSee signals.yaml for double-tap behavior definition.",
2324
- category: "signals",
2325
- bsdEquivalent: "128 + 2"
2326
- },
2327
- 131: {
2328
- code: 131,
2329
- name: "EXIT_SIGNAL_QUIT",
2330
- description: "Quit signal (SIGQUIT) - immediate exit",
2331
- context: "Ctrl+\\ on Unix, Ctrl+Break on Windows. Immediate termination without cleanup.\nUse for emergency shutdown or debugging (core dumps).",
2332
- category: "signals",
2333
- bsdEquivalent: "128 + 3"
2334
- },
2335
- 137: {
2336
- code: 137,
2337
- name: "EXIT_SIGNAL_KILL",
2338
- description: "Kill signal (SIGKILL)",
2339
- context: "Forceful termination, non-graceful shutdown (not catchable)",
2340
- category: "signals",
2341
- bsdEquivalent: "128 + 9",
2342
- pythonNote: "Cannot be caught in Python (OS-level)"
2343
- },
2344
- 141: {
2345
- code: 141,
2346
- name: "EXIT_SIGNAL_PIPE",
2347
- description: "Broken pipe (SIGPIPE) - observe only",
2348
- context: "Writing to closed pipe/socket. Fulmen default is observe_only (log + graceful exit).\nApplications may override to ignore for network services.\nSee signals.yaml for SIGPIPE handling guidance.",
2349
- category: "signals",
2350
- bsdEquivalent: "128 + 13",
2351
- pythonNote: "Raised as BrokenPipeError exception"
2352
- },
2353
- 142: {
2354
- code: 142,
2355
- name: "EXIT_SIGNAL_ALRM",
2356
- description: "Alarm signal (SIGALRM) - watchdog timeout",
2357
- context: "Watchdog timer expired. Treat as timeout-induced exit.\nWatchdog pattern out of scope for v1.0.0 module implementations.",
2358
- category: "signals",
2359
- bsdEquivalent: "128 + 14",
2360
- pythonNote: "Supported by signal module, rarely used in practice"
2361
- },
2362
- 143: {
2363
- code: 143,
2364
- name: "EXIT_SIGNAL_TERM",
2365
- description: "Termination signal (SIGTERM) - graceful shutdown",
2366
- context: "Graceful shutdown requested by container orchestrator or process supervisor.\nStandard 30-second timeout for cleanup. Applications run cleanup handlers before exit.\nSee signals.yaml for graceful shutdown behavior definition.",
2367
- category: "signals",
2368
- bsdEquivalent: "128 + 15",
2369
- pythonNote: "Default signal for graceful shutdown"
2370
- },
2371
- 138: {
2372
- code: 138,
2373
- name: "EXIT_SIGNAL_USR1",
2374
- description: "User-defined signal 1 (SIGUSR1) - custom handler",
2375
- context: "Application-specific signal (e.g., reopen logs, dump stats, trigger profiling).\nApplications register custom handlers. Exit code 138 on Linux (128+10).\nPlatform differences: macOS/FreeBSD use signal 30 (exit 158), not 10.",
2376
- category: "signals"
2377
- },
2378
- 140: {
2379
- code: 140,
2380
- name: "EXIT_SIGNAL_USR2",
2381
- description: "User-defined signal 2 (SIGUSR2) - custom handler",
2382
- context: "Application-specific signal (e.g., toggle debug mode, rotate credentials).\nApplications register custom handlers. Exit code 140 on Linux (128+12).\nPlatform differences: macOS/FreeBSD use signal 31 (exit 159), not 12.",
2383
- category: "signals"
2384
- }
2385
- };
2386
- EXIT_CODES_VERSION = "v1.0.0";
2387
- }
2388
- });
2389
-
2390
- // src/foundry/exit-codes/capabilities.ts
2391
- function supportsSignalExitCodes() {
2392
- return process.platform !== "win32";
2393
- }
2394
- function getPlatform() {
2395
- return process.platform;
2396
- }
2397
- function isWindows() {
2398
- return process.platform === "win32";
2399
- }
2400
- function isPOSIX() {
2401
- return !isWindows();
2402
- }
2403
- function getPlatformCapabilities() {
2404
- return {
2405
- platform: getPlatform(),
2406
- supportsSignalExitCodes: supportsSignalExitCodes(),
2407
- isPOSIX: isPOSIX(),
2408
- isWindows: isWindows()
2409
- };
2410
- }
2411
- var init_capabilities = __esm({
2412
- "src/foundry/exit-codes/capabilities.ts"() {
2413
- }
2414
- });
2415
-
2416
- // src/foundry/exit-codes/simplified.ts
2417
- function mapExitCodeToSimplified(code, mode = "basic" /* BASIC */) {
2418
- if (code === 0) {
2419
- return 0;
2420
- }
2421
- if (mode === "basic" /* BASIC */) {
2422
- return 1;
2423
- }
2424
- const info = exitCodeMetadata[code];
2425
- if (!info) {
2426
- return 3;
2427
- }
2428
- if (info.retryHint === "retry") {
2429
- return 1;
2430
- }
2431
- if (info.retryHint === "no_retry") {
2432
- return 2;
2433
- }
2434
- if (info.retryHint === "investigate") {
2435
- return 3;
2436
- }
2437
- switch (info.category) {
2438
- case "configuration":
2439
- case "usage":
2440
- return 2;
2441
- case "networking":
2442
- case "runtime":
2443
- return 1;
2444
- case "permissions":
2445
- case "data":
2446
- return 2;
2447
- case "security":
2448
- return 3;
2449
- case "observability":
2450
- return 1;
2451
- case "testing":
2452
- return 1;
2453
- case "signals":
2454
- return 3;
2455
- default:
2456
- return 1;
2457
- }
2458
- }
2459
- function getSimplifiedCodes(mode) {
2460
- switch (mode) {
2461
- case "basic" /* BASIC */:
2462
- return [0, 1];
2463
- case "severity" /* SEVERITY */:
2464
- return [0, 1, 2, 3];
2465
- default:
2466
- return [0, 1];
2467
- }
2468
- }
2469
- function getSimplifiedCodeDescription(code, mode) {
2470
- if (mode === "basic" /* BASIC */) {
2471
- switch (code) {
2472
- case 0:
2473
- return "Success";
2474
- case 1:
2475
- return "Failure";
2476
- default:
2477
- return "Unknown";
2478
- }
2479
- }
2480
- if (mode === "severity" /* SEVERITY */) {
2481
- switch (code) {
2482
- case 0:
2483
- return "Success";
2484
- case 1:
2485
- return "Recoverable error (retry possible)";
2486
- case 2:
2487
- return "Configuration error (fix config, don't retry)";
2488
- case 3:
2489
- return "Fatal error (investigate required)";
2490
- default:
2491
- return "Unknown";
2492
- }
2493
- }
2494
- return "Unknown mode";
2495
- }
2496
- var SimplifiedMode;
2497
- var init_simplified = __esm({
2498
- "src/foundry/exit-codes/simplified.ts"() {
2499
- init_exitCodes();
2500
- SimplifiedMode = /* @__PURE__ */ ((SimplifiedMode2) => {
2501
- SimplifiedMode2["BASIC"] = "basic";
2502
- SimplifiedMode2["SEVERITY"] = "severity";
2503
- return SimplifiedMode2;
2504
- })(SimplifiedMode || {});
2505
- }
2506
- });
2507
-
2508
- // src/foundry/exit-codes/index.ts
2509
- var init_exit_codes = __esm({
2510
- "src/foundry/exit-codes/index.ts"() {
2511
- init_exitCodes();
2512
- init_capabilities();
2513
- init_simplified();
2514
- }
2515
- });
2516
-
2517
- // src/foundry/http-statuses.ts
2518
- function deepClone2(obj) {
2519
- if (obj === null || typeof obj !== "object") {
2520
- return obj;
2521
- }
2522
- if (Array.isArray(obj)) {
2523
- return obj.map((item) => deepClone2(item));
2524
- }
2525
- const cloned = {};
2526
- for (const key in obj) {
2527
- if (Object.hasOwn(obj, key)) {
2528
- cloned[key] = deepClone2(obj[key]);
2529
- }
2530
- }
2531
- return cloned;
2532
- }
2533
- function deepFreeze2(obj) {
2534
- Object.freeze(obj);
2535
- for (const key in obj) {
2536
- if (Object.hasOwn(obj, key)) {
2537
- const value = obj[key];
2538
- if (value !== null && typeof value === "object") {
2539
- deepFreeze2(value);
2540
- }
2541
- }
2542
- }
2543
- return obj;
2544
- }
2545
- async function ensureCatalogLoaded2() {
2546
- if (catalogCache2 !== null) {
2547
- return;
2548
- }
2549
- catalogCache2 = await loadHttpStatusCatalog();
2550
- for (const group of catalogCache2.groups) {
2551
- const groupId = group.id;
2552
- for (const code of group.codes) {
2553
- statusCodeIndex.set(code.value, {
2554
- value: code.value,
2555
- reason: code.reason,
2556
- group: groupId
2557
- });
2558
- }
2559
- }
2560
- }
2561
- async function getHttpStatus(code) {
2562
- await ensureCatalogLoaded2();
2563
- const status = statusCodeIndex.get(code);
2564
- return status ? deepFreeze2(deepClone2(status)) : null;
2565
- }
2566
- function isInformational(code) {
2567
- return code >= 100 && code < 200;
2568
- }
2569
- function isSuccess(code) {
2570
- return code >= 200 && code < 300;
2571
- }
2572
- function isRedirection(code) {
2573
- return code >= 300 && code < 400;
2574
- }
2575
- function isClientError(code) {
2576
- return code >= 400 && code < 500;
2577
- }
2578
- function isServerError(code) {
2579
- return code >= 500 && code < 600;
2580
- }
2581
- async function listHttpStatuses() {
2582
- await ensureCatalogLoaded2();
2583
- return Array.from(statusCodeIndex.values()).map((s) => deepFreeze2(deepClone2(s)));
2584
- }
2585
- async function getStatusReason(code) {
2586
- const status = await getHttpStatus(code);
2587
- return status?.reason ?? null;
2588
- }
2589
- function clearHttpStatusCache() {
2590
- catalogCache2 = null;
2591
- statusCodeIndex.clear();
2592
- }
2593
- var catalogCache2, statusCodeIndex;
2594
- var init_http_statuses = __esm({
2595
- "src/foundry/http-statuses.ts"() {
2596
- init_loader();
2597
- catalogCache2 = null;
2598
- statusCodeIndex = /* @__PURE__ */ new Map();
2599
- }
2600
- });
2601
-
2602
- // src/foundry/magic-numbers.ts
2603
- function hasBOM(buffer) {
2604
- if (buffer.length < 3) return false;
2605
- return buffer[0] === UTF8_BOM[0] && buffer[1] === UTF8_BOM[1] && buffer[2] === UTF8_BOM[2];
2606
- }
2607
- function getBOMOffset(buffer) {
2608
- return hasBOM(buffer) ? 3 : 0;
2609
- }
2610
- var UTF8_BOM, XML_PATTERNS, JSON_PATTERNS, YAML_PATTERNS, NDJSON_PATTERNS, CSV_PATTERNS, PROTOBUF_PATTERNS, TEXT_PATTERNS, MAGIC_NUMBER_DATABASE;
2611
- var init_magic_numbers = __esm({
2612
- "src/foundry/magic-numbers.ts"() {
2613
- UTF8_BOM = [239, 187, 191];
2614
- XML_PATTERNS = [
2615
- {
2616
- offset: 0,
2617
- bytes: [60, 63, 120, 109, 108],
2618
- description: "XML declaration: <?xml"
2619
- },
2620
- {
2621
- offset: 0,
2622
- bytes: [239, 187, 191, 60, 63, 120, 109, 108],
2623
- description: "XML with UTF-8 BOM: BOM + <?xml"
2624
- }
2625
- ];
2626
- JSON_PATTERNS = [
2627
- {
2628
- offset: 0,
2629
- bytes: [123],
2630
- description: "JSON object start: {"
2631
- },
2632
- {
2633
- offset: 0,
2634
- bytes: [91],
2635
- description: "JSON array start: ["
2636
- },
2637
- {
2638
- offset: 0,
2639
- bytes: [239, 187, 191, 123],
2640
- description: "JSON object with BOM: BOM + {"
2641
- },
2642
- {
2643
- offset: 0,
2644
- bytes: [239, 187, 191, 91],
2645
- description: "JSON array with BOM: BOM + ["
2646
- }
2647
- ];
2648
- YAML_PATTERNS = [
2649
- {
2650
- offset: 0,
2651
- bytes: [45, 45, 45],
2652
- description: "YAML document marker: ---"
2653
- },
2654
- {
2655
- offset: 0,
2656
- bytes: [37, 89, 65, 77, 76],
2657
- description: "YAML directive: %YAML"
2658
- }
2659
- ];
2660
- NDJSON_PATTERNS = [];
2661
- CSV_PATTERNS = [];
2662
- PROTOBUF_PATTERNS = [];
2663
- TEXT_PATTERNS = [];
2664
- MAGIC_NUMBER_DATABASE = [
2665
- {
2666
- mimeType: "application/xml",
2667
- patterns: XML_PATTERNS,
2668
- priority: 10,
2669
- matchStrategy: "exact"
2670
- },
2671
- {
2672
- mimeType: "application/x-ndjson",
2673
- patterns: NDJSON_PATTERNS,
2674
- priority: 9,
2675
- matchStrategy: "heuristic"
2676
- },
2677
- {
2678
- mimeType: "application/json",
2679
- patterns: JSON_PATTERNS,
2680
- priority: 8,
2681
- matchStrategy: "exact"
2682
- },
2683
- {
2684
- mimeType: "application/yaml",
2685
- patterns: YAML_PATTERNS,
2686
- priority: 7,
2687
- matchStrategy: "exact"
2688
- },
2689
- {
2690
- mimeType: "application/yaml",
2691
- patterns: [],
2692
- priority: 6.5,
2693
- matchStrategy: "heuristic"
2694
- },
2695
- {
2696
- mimeType: "text/csv",
2697
- patterns: CSV_PATTERNS,
2698
- priority: 6,
2699
- matchStrategy: "heuristic"
2700
- },
2701
- {
2702
- mimeType: "application/x-protobuf",
2703
- patterns: PROTOBUF_PATTERNS,
2704
- priority: 5,
2705
- matchStrategy: "heuristic"
2706
- },
2707
- {
2708
- mimeType: "text/plain",
2709
- patterns: TEXT_PATTERNS,
2710
- priority: 1,
2711
- matchStrategy: "heuristic"
2712
- }
2713
- ];
2714
- }
2715
- });
2716
-
2717
- // src/foundry/detector.ts
2718
- function createDetector(catalog) {
2719
- return new MimeTypeDetector(MAGIC_NUMBER_DATABASE, catalog);
2720
- }
2721
- var MimeTypeDetector;
2722
- var init_detector = __esm({
2723
- "src/foundry/detector.ts"() {
2724
- init_magic_numbers();
2725
- MimeTypeDetector = class {
2726
- patterns;
2727
- catalog;
2728
- constructor(patterns, catalog) {
2729
- this.patterns = [...patterns].sort((a, b) => b.priority - a.priority);
2730
- this.catalog = catalog;
2731
- }
2732
- /**
2733
- * Detect MIME type from buffer content
2734
- */
2735
- detect(buffer, _options = {}) {
2736
- const offset = getBOMOffset(buffer);
2737
- const workingBuffer = offset > 0 ? buffer.subarray(offset) : buffer;
2738
- for (const pattern of this.patterns) {
2739
- if (pattern.matchStrategy === "exact" && this.matchPattern(workingBuffer, pattern)) {
2740
- return this.catalog.get(pattern.mimeType) || null;
2741
- }
2742
- if (pattern.matchStrategy === "heuristic" && this.matchHeuristic(workingBuffer, pattern)) {
2743
- return this.catalog.get(pattern.mimeType) || null;
2744
- }
2745
- }
2746
- return null;
2747
- }
2748
- /**
2749
- * Match buffer against a pattern signature
2750
- */
2751
- matchPattern(buffer, signature) {
2752
- for (const pattern of signature.patterns) {
2753
- if (this.matchBytes(buffer, pattern)) {
2754
- return true;
2755
- }
2756
- }
2757
- return false;
2758
- }
2759
- /**
2760
- * Match bytes at specified offset with optional masking
2761
- */
2762
- matchBytes(buffer, pattern) {
2763
- const { offset, bytes, mask } = pattern;
2764
- if (buffer.length < offset + bytes.length) {
2765
- return false;
2766
- }
2767
- for (let i = 0; i < bytes.length; i++) {
2768
- const bufferByte = buffer[offset + i];
2769
- const patternByte = bytes[i];
2770
- const maskByte = mask ? mask[i] : 255;
2771
- if ((bufferByte & maskByte) !== (patternByte & maskByte)) {
2772
- return false;
2773
- }
2774
- }
2775
- return true;
2776
- }
2777
- /**
2778
- * Heuristic detection for formats without magic numbers
2779
- */
2780
- matchHeuristic(buffer, signature) {
2781
- switch (signature.mimeType) {
2782
- case "application/x-ndjson":
2783
- return this.detectNDJSON(buffer);
2784
- case "application/yaml":
2785
- return this.detectYAML(buffer);
2786
- case "text/csv":
2787
- return this.detectCSV(buffer);
2788
- case "application/x-protobuf":
2789
- return this.detectProtobuf(buffer);
2790
- case "text/plain":
2791
- return this.detectPlainText(buffer);
2792
- default:
2793
- return false;
2794
- }
2795
- }
2796
- /**
2797
- * Detect NDJSON (newline-delimited JSON)
2798
- */
2799
- detectNDJSON(buffer) {
2800
- try {
2801
- const text = buffer.toString("utf-8", 0, Math.min(buffer.length, 512));
2802
- const lines = text.split("\n").filter((line) => line.trim().length > 0);
2803
- if (lines.length < 2) return false;
2804
- const linesToCheck = Math.min(3, lines.length);
2805
- let validJsonLines = 0;
2806
- for (let i = 0; i < linesToCheck; i++) {
2807
- try {
2808
- JSON.parse(lines[i]);
2809
- validJsonLines++;
2810
- } catch {
2811
- return false;
2812
- }
2813
- }
2814
- return validJsonLines >= 2;
2815
- } catch {
2816
- return false;
2817
- }
2818
- }
2819
- /**
2820
- * Detect YAML format (heuristic for files without --- header)
2821
- */
2822
- detectYAML(buffer) {
2823
- try {
2824
- const text = buffer.toString("utf-8", 0, Math.min(buffer.length, 512));
2825
- const lines = text.split("\n").filter((line) => line.trim().length > 0);
2826
- if (lines.length === 0) return false;
2827
- let yamlIndicators = 0;
2828
- let nonYamlIndicators = 0;
2829
- for (const line of lines.slice(0, 10)) {
2830
- const trimmed = line.trim();
2831
- if (trimmed.startsWith("#")) continue;
2832
- if (/^[\w"'-]+\s*:\s*.+$/.test(trimmed)) {
2833
- yamlIndicators++;
2834
- continue;
2835
- }
2836
- if (/^-\s+/.test(trimmed)) {
2837
- yamlIndicators++;
2838
- continue;
2839
- }
2840
- if (trimmed.startsWith("{") || trimmed.startsWith("[") || trimmed.endsWith(",")) {
2841
- nonYamlIndicators++;
2842
- }
2843
- }
2844
- return yamlIndicators >= 2 && nonYamlIndicators === 0;
2845
- } catch {
2846
- return false;
2847
- }
2848
- }
2849
- /**
2850
- * Detect CSV format
2851
- */
2852
- detectCSV(buffer) {
2853
- try {
2854
- const text = buffer.toString("utf-8", 0, Math.min(buffer.length, 512));
2855
- const lines = text.split("\n").filter((line) => line.trim().length > 0);
2856
- if (lines.length < 2) return false;
2857
- const delimiters = [",", ";", " "];
2858
- for (const delimiter of delimiters) {
2859
- const counts = lines.map((line) => {
2860
- const escaped = delimiter.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2861
- const matches = line.match(new RegExp(escaped, "g"));
2862
- return matches ? matches.length : 0;
2863
- });
2864
- const firstCount = counts[0];
2865
- if (firstCount > 0 && counts.every((count) => count === firstCount)) {
2866
- return true;
2867
- }
2868
- }
2869
- return false;
2870
- } catch {
2871
- return false;
2872
- }
2873
- }
2874
- /**
2875
- * Detect protobuf binary format
2876
- */
2877
- detectProtobuf(buffer) {
2878
- if (buffer.length < 4) return false;
2879
- const firstByte = buffer[0];
2880
- const wireType = firstByte & 7;
2881
- const fieldNumber = firstByte >> 3;
2882
- const hasValidWireType = wireType === 0 || wireType === 1 || wireType === 2 || wireType === 5;
2883
- const hasValidFieldNumber = fieldNumber > 0 && fieldNumber < 100;
2884
- const isBinary = this.isBinaryContent(buffer);
2885
- return hasValidWireType && hasValidFieldNumber && isBinary;
2886
- }
2887
- /**
2888
- * Detect plain text format
2889
- */
2890
- detectPlainText(buffer) {
2891
- const sample = buffer.subarray(0, Math.min(buffer.length, 512));
2892
- if (sample.length === 0) return false;
2893
- let binaryBytes = 0;
2894
- for (const byte of sample) {
2895
- if (byte === 0 || byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {
2896
- binaryBytes++;
2897
- }
2898
- }
2899
- return binaryBytes / sample.length < 0.05;
2900
- }
2901
- /**
2902
- * Check if buffer contains binary content
2903
- */
2904
- isBinaryContent(buffer) {
2905
- const sample = buffer.subarray(0, Math.min(buffer.length, 512));
2906
- let binaryBytes = 0;
2907
- for (const byte of sample) {
2908
- if (byte === 0 || byte < 32 && byte !== 9 && byte !== 10 && byte !== 13) {
2909
- binaryBytes++;
2910
- }
2911
- }
2912
- return binaryBytes / sample.length > 0.1;
2913
- }
2914
- };
2915
- }
2916
- });
2917
- function deepClone3(obj) {
2918
- if (obj === null || typeof obj !== "object") {
2919
- return obj;
2920
- }
2921
- if (Array.isArray(obj)) {
2922
- return obj.map((item) => deepClone3(item));
2923
- }
2924
- const cloned = {};
2925
- for (const key in obj) {
2926
- if (Object.hasOwn(obj, key)) {
2927
- cloned[key] = deepClone3(obj[key]);
2928
- }
2929
- }
2930
- return cloned;
2931
- }
2932
- function deepFreeze3(obj) {
2933
- Object.freeze(obj);
2934
- for (const key in obj) {
2935
- if (Object.hasOwn(obj, key)) {
2936
- const value = obj[key];
2937
- if (value !== null && typeof value === "object") {
2938
- deepFreeze3(value);
2939
- }
2940
- }
2941
- }
2942
- return obj;
2943
- }
2944
- async function ensureCatalogLoaded3() {
2945
- if (catalogCache3 !== null) {
2946
- return;
2947
- }
2948
- catalogCache3 = await loadMimeTypeCatalog();
2949
- for (const mimeType of catalogCache3.types) {
2950
- mimeStringIndex.set(mimeType.mime.toLowerCase(), mimeType);
2951
- for (const ext of mimeType.extensions) {
2952
- const normalized = ext.toLowerCase().replace(/^\./, "");
2953
- extensionIndex.set(normalized, mimeType);
2954
- }
2955
- }
2956
- detectorInstance = createDetector(mimeStringIndex);
2957
- }
2958
- async function getMimeType(mimeString) {
2959
- await ensureCatalogLoaded3();
2960
- const normalized = mimeString.toLowerCase();
2961
- const mimeType = mimeStringIndex.get(normalized);
2962
- return mimeType ? deepFreeze3(deepClone3(mimeType)) : null;
2963
- }
2964
- async function getMimeTypeByExtension(extension) {
2965
- await ensureCatalogLoaded3();
2966
- const normalized = extension.toLowerCase().replace(/^\./, "");
2967
- const mimeType = extensionIndex.get(normalized);
2968
- return mimeType ? deepFreeze3(deepClone3(mimeType)) : null;
2969
- }
2970
- async function isSupportedMimeType(mime) {
2971
- await ensureCatalogLoaded3();
2972
- return mimeStringIndex.has(mime.toLowerCase());
2973
- }
2974
- async function detectMimeType(input, options) {
2975
- await ensureCatalogLoaded3();
2976
- if (!detectorInstance) {
2977
- throw new Error("Detector not initialized");
2978
- }
2979
- if (typeof input === "string") {
2980
- return detectMimeTypeFromFile(input, options);
2981
- }
2982
- if (Buffer.isBuffer(input)) {
2983
- return detectMimeTypeFromBuffer(input, options);
2984
- }
2985
- return detectMimeTypeFromStream(input, options);
2986
- }
2987
- async function detectMimeTypeFromFile(filePath, options = {}) {
2988
- await ensureCatalogLoaded3();
2989
- if (!detectorInstance) {
2990
- throw new Error("Detector not initialized");
2991
- }
2992
- const bytesToRead = options.bytesToRead || 512;
2993
- if (typeof Bun !== "undefined") {
2994
- const file = Bun.file(filePath);
2995
- if (!await file.exists()) {
2996
- return null;
2997
- }
2998
- const slice = file.slice(0, bytesToRead);
2999
- const arrayBuffer = await slice.arrayBuffer();
3000
- const buffer = Buffer.from(arrayBuffer);
3001
- return detectMimeTypeFromBuffer(buffer, options);
3002
- }
3003
- try {
3004
- const buffer = await readFile(filePath, { encoding: null });
3005
- const sample = buffer.subarray(0, Math.min(buffer.length, bytesToRead));
3006
- return detectMimeTypeFromBuffer(sample, options);
3007
- } catch (error) {
3008
- if (error.code === "ENOENT") {
3009
- return null;
3010
- }
3011
- throw error;
3012
- }
3013
- }
3014
- function detectMimeTypeFromBuffer(buffer, options = {}) {
3015
- if (!detectorInstance) {
3016
- throw new Error("Detector not initialized");
3017
- }
3018
- const result = detectorInstance.detect(buffer, options);
3019
- return result ? deepFreeze3(deepClone3(result)) : null;
3020
- }
3021
- async function detectMimeTypeFromStream(stream, options = {}) {
3022
- await ensureCatalogLoaded3();
3023
- const bytesToRead = options.bytesToRead || 512;
3024
- const chunks = [];
3025
- let totalBytes = 0;
3026
- const webStream = typeof stream.getReader === "function" ? stream : Readable.toWeb(stream);
3027
- const reader = webStream.getReader();
3028
- try {
3029
- while (totalBytes < bytesToRead) {
3030
- const { value, done } = await reader.read();
3031
- if (done) break;
3032
- chunks.push(value);
3033
- totalBytes += value.length;
3034
- }
3035
- const buffer = Buffer.concat(chunks.map((c) => Buffer.from(c)));
3036
- const sample = buffer.subarray(0, Math.min(buffer.length, bytesToRead));
3037
- return detectMimeTypeFromBuffer(sample, options);
3038
- } finally {
3039
- reader.releaseLock();
3040
- }
3041
- }
3042
- function matchMagicNumber(buffer, mimeType) {
3043
- if (!detectorInstance) {
3044
- throw new Error("Detector not initialized");
3045
- }
3046
- const result = detectorInstance.detect(buffer);
3047
- return result?.mime === mimeType;
3048
- }
3049
- async function listMimeTypes() {
3050
- await ensureCatalogLoaded3();
3051
- return Array.from(mimeStringIndex.values()).map((m) => deepFreeze3(deepClone3(m)));
3052
- }
3053
- function clearMimeTypeCache() {
3054
- catalogCache3 = null;
3055
- mimeStringIndex.clear();
3056
- extensionIndex.clear();
3057
- detectorInstance = null;
3058
- }
3059
- var catalogCache3, mimeStringIndex, extensionIndex, detectorInstance;
3060
- var init_mime_types = __esm({
3061
- "src/foundry/mime-types.ts"() {
3062
- init_detector();
3063
- init_loader();
3064
- catalogCache3 = null;
3065
- mimeStringIndex = /* @__PURE__ */ new Map();
3066
- extensionIndex = /* @__PURE__ */ new Map();
3067
- detectorInstance = null;
3068
- }
3069
- });
3070
- function deepClone4(obj) {
3071
- if (obj === null || typeof obj !== "object") {
3072
- return obj;
3073
- }
3074
- if (Array.isArray(obj)) {
3075
- return obj.map((item) => deepClone4(item));
3076
- }
3077
- const cloned = {};
3078
- for (const key in obj) {
3079
- if (Object.hasOwn(obj, key)) {
3080
- cloned[key] = deepClone4(obj[key]);
3081
- }
3082
- }
3083
- return cloned;
3084
- }
3085
- function deepFreeze4(obj) {
3086
- Object.freeze(obj);
3087
- for (const key in obj) {
3088
- if (Object.hasOwn(obj, key)) {
3089
- const value = obj[key];
3090
- if (value !== null && typeof value === "object") {
3091
- deepFreeze4(value);
3092
- }
3093
- }
3094
- }
3095
- return obj;
3096
- }
3097
- async function ensureCatalogLoaded4() {
3098
- if (catalogCache4 !== null) {
3099
- return;
3100
- }
3101
- catalogCache4 = await loadPatternCatalog();
3102
- for (const pattern of catalogCache4.patterns) {
3103
- patternIndex.set(pattern.id, pattern);
3104
- }
3105
- }
3106
- async function getPattern(id) {
3107
- await ensureCatalogLoaded4();
3108
- const pattern = patternIndex.get(id);
3109
- return pattern ? deepFreeze4(deepClone4(pattern)) : null;
3110
- }
3111
- async function getPatternRegex(id) {
3112
- await ensureCatalogLoaded4();
3113
- const pattern = patternIndex.get(id);
3114
- if (!pattern) {
3115
- return null;
3116
- }
3117
- if (pattern.kind !== "regex") {
3118
- throw FoundryCatalogError.invalidSchema(
3119
- "patterns",
3120
- `Pattern '${id}' is not a regex pattern (kind: ${pattern.kind})`
3121
- );
3122
- }
3123
- const cached = compiledRegexCache.get(id);
3124
- if (cached !== void 0) {
3125
- return cached;
3126
- }
3127
- let flags = "";
3128
- if (pattern.flags?.typescript?.ignoreCase) {
3129
- flags += "i";
3130
- }
3131
- const hasUnicodePropertyEscapes = /\\p\{/.test(pattern.pattern);
3132
- if (pattern.flags?.typescript?.unicode || hasUnicodePropertyEscapes) {
3133
- flags += "u";
3134
- }
3135
- const regex = new RegExp(pattern.pattern, flags);
3136
- compiledRegexCache.set(id, regex);
3137
- return regex;
3138
- }
3139
- function getCompiledGlob(id, pattern) {
3140
- const cached = compiledGlobCache.get(id);
3141
- if (cached !== void 0) {
3142
- return cached;
3143
- }
3144
- const matcher = picomatch(pattern);
3145
- compiledGlobCache.set(id, matcher);
3146
- return matcher;
3147
- }
3148
- async function matchPattern(id, value) {
3149
- await ensureCatalogLoaded4();
3150
- const pattern = patternIndex.get(id);
3151
- if (!pattern) {
3152
- throw FoundryCatalogError.missingCatalog(`Pattern '${id}' not found`);
3153
- }
3154
- if (pattern.kind === "regex") {
3155
- const regex = await getPatternRegex(id);
3156
- return regex ? regex.test(value) : false;
3157
- }
3158
- if (pattern.kind === "glob") {
3159
- const matcher = getCompiledGlob(id, pattern.pattern);
3160
- return matcher(value);
3161
- }
3162
- if (pattern.kind === "literal") {
3163
- return pattern.pattern === value;
3164
- }
3165
- throw FoundryCatalogError.invalidSchema("patterns", `Unknown pattern kind: ${pattern.kind}`);
3166
- }
3167
- async function listPatterns() {
3168
- await ensureCatalogLoaded4();
3169
- return Array.from(patternIndex.values()).map((p) => deepFreeze4(deepClone4(p)));
3170
- }
3171
- async function describePattern(id) {
3172
- const pattern = await getPattern(id);
3173
- return pattern?.description ?? null;
3174
- }
3175
- function clearPatternCache() {
3176
- catalogCache4 = null;
3177
- patternIndex.clear();
3178
- compiledRegexCache.clear();
3179
- compiledGlobCache.clear();
3180
- }
3181
- var catalogCache4, patternIndex, compiledRegexCache, compiledGlobCache;
3182
- var init_patterns = __esm({
3183
- "src/foundry/patterns.ts"() {
3184
- init_errors2();
3185
- init_loader();
3186
- catalogCache4 = null;
3187
- patternIndex = /* @__PURE__ */ new Map();
3188
- compiledRegexCache = /* @__PURE__ */ new Map();
3189
- compiledGlobCache = /* @__PURE__ */ new Map();
3190
- }
3191
- });
3192
- function distance(a, b, metric = "levenshtein") {
3193
- switch (metric) {
3194
- case "levenshtein":
3195
- return levenshtein(a, b);
3196
- case "damerau_osa":
3197
- return osa_distance(a, b);
3198
- case "damerau_unrestricted":
3199
- return damerau_levenshtein(a, b);
3200
- case "jaro_winkler":
3201
- return jaro_winkler(a, b);
3202
- case "substring":
3203
- return substringSimilarity(a, b).score;
3204
- default:
3205
- throw new Error(
3206
- `Invalid metric '${metric}': must be one of: levenshtein, damerau_osa, damerau_unrestricted, jaro_winkler, substring`
3207
- );
3208
- }
3209
- }
3210
- var init_distance = __esm({
3211
- "src/foundry/similarity/distance.ts"() {
3212
- }
3213
- });
3214
-
3215
- // src/foundry/similarity/errors.ts
3216
- var init_errors3 = __esm({
3217
- "src/foundry/similarity/errors.ts"() {
3218
- init_errors2();
3219
- }
3220
- });
3221
- function toNormalizationLocale(locale) {
3222
- if (!locale) {
3223
- return void 0;
3224
- }
3225
- if (locale === "tr" || locale === "az" || locale === "lt") {
3226
- return locale;
3227
- }
3228
- return void 0;
3229
- }
3230
- function normalize(value, preset = "default", locale) {
3231
- if (typeof preset === "object") {
3232
- const targetPreset = preset.stripAccents ? "aggressive" : "default";
3233
- const targetLocale = toNormalizationLocale(preset.locale ?? locale);
3234
- return normalize$1(value, targetPreset, targetLocale);
3235
- }
3236
- return normalize$1(value, preset, toNormalizationLocale(locale));
3237
- }
3238
- function casefold(value, locale) {
3239
- if (locale === "tr") {
3240
- return value.toLocaleLowerCase("tr-TR");
3241
- }
3242
- return value.toLowerCase();
3243
- }
3244
- function stripAccents(value) {
3245
- return value.normalize("NFD").replace(/[\u0300-\u036f]/g, "");
3246
- }
3247
- function equalsIgnoreCase(a, b, options) {
3248
- return normalize(a, options) === normalize(b, options);
3249
- }
3250
- var init_normalization = __esm({
3251
- "src/foundry/similarity/normalization.ts"() {
3252
- }
3253
- });
3254
- function score(a, b, metric = "levenshtein") {
3255
- if (metric === "substring") {
3256
- return substringSimilarity(a, b).score;
3257
- }
3258
- return score$1(a, b, metric);
3259
- }
3260
- var init_score = __esm({
3261
- "src/foundry/similarity/score.ts"() {
3262
- }
3263
- });
3264
- function suggest(input, candidates, options) {
3265
- const metric = options?.metric ?? DEFAULT_METRIC;
3266
- const minScore = options?.minScore ?? DEFAULT_MIN_SCORE;
3267
- const maxSuggestions = options?.maxSuggestions ?? DEFAULT_MAX_SUGGESTIONS;
3268
- let normalizePreset = options?.normalizePreset ?? DEFAULT_NORMALIZE_PRESET;
3269
- if (options?.normalize === false) {
3270
- normalizePreset = "none";
3271
- } else if (options?.normalize === true && !options?.normalizePreset) {
3272
- normalizePreset = "default";
3273
- }
3274
- const wasmOptions = {
3275
- metric,
3276
- normalizePreset,
3277
- minScore,
3278
- maxSuggestions,
3279
- preferPrefix: options?.preferPrefix,
3280
- jaroPrefixScale: options?.jaroPrefixScale,
3281
- jaroMaxPrefix: options?.jaroMaxPrefix
3282
- };
3283
- const results = suggest$1(input, candidates, wasmOptions);
3284
- return results.map((r) => ({
3285
- value: r.value,
3286
- score: r.score,
3287
- matchedRange: r.matchedRange,
3288
- reason: r.reason,
3289
- normalizedValue: r.normalizedValue
3290
- }));
3291
- }
3292
- var DEFAULT_MIN_SCORE, DEFAULT_MAX_SUGGESTIONS, DEFAULT_METRIC, DEFAULT_NORMALIZE_PRESET;
3293
- var init_suggest = __esm({
3294
- "src/foundry/similarity/suggest.ts"() {
3295
- DEFAULT_MIN_SCORE = 0.6;
3296
- DEFAULT_MAX_SUGGESTIONS = 3;
3297
- DEFAULT_METRIC = "levenshtein";
3298
- DEFAULT_NORMALIZE_PRESET = "default";
3299
- }
3300
- });
3301
-
3302
- // src/foundry/similarity/index.ts
3303
- var init_similarity = __esm({
3304
- "src/foundry/similarity/index.ts"() {
3305
- init_distance();
3306
- init_errors3();
3307
- init_normalization();
3308
- init_score();
3309
- init_suggest();
3310
- }
3311
- });
3312
-
3313
- // src/foundry/index.ts
3314
- var foundry_exports = {};
3315
- __export(foundry_exports, {
3316
- ConfigReloadTracker: () => ConfigReloadTracker,
3317
- EXIT_CODES_VERSION: () => EXIT_CODES_VERSION,
3318
- FoundryCatalogError: () => FoundryCatalogError,
3319
- SignalManager: () => SignalManager,
3320
- SimplifiedMode: () => SimplifiedMode,
3321
- VERSION: () => VERSION,
3322
- casefold: () => casefold,
3323
- clearCountryCodeCache: () => clearCountryCodeCache,
3324
- clearHttpStatusCache: () => clearHttpStatusCache,
3325
- clearMimeTypeCache: () => clearMimeTypeCache,
3326
- clearPatternCache: () => clearPatternCache,
3327
- createBearerTokenAuth: () => createBearerTokenAuth,
3328
- createConfigReloadEndpoint: () => createConfigReloadEndpoint,
3329
- createConfigReloadHandler: () => createConfigReloadHandler,
3330
- createControlDiscoveryEndpoint: () => createControlDiscoveryEndpoint,
3331
- createDoubleTapTracker: () => createDoubleTapTracker,
3332
- createSignalEndpoint: () => createSignalEndpoint,
3333
- createSignalManager: () => createSignalManager,
3334
- createSimpleRateLimiter: () => createSimpleRateLimiter,
3335
- describePattern: () => describePattern,
3336
- detectMimeType: () => detectMimeType,
3337
- detectMimeTypeFromBuffer: () => detectMimeTypeFromBuffer,
3338
- detectMimeTypeFromFile: () => detectMimeTypeFromFile,
3339
- detectMimeTypeFromStream: () => detectMimeTypeFromStream,
3340
- distance: () => distance,
3341
- ensurePOSIX: () => ensurePOSIX,
3342
- ensureSignalExitCodesSupported: () => ensureSignalExitCodesSupported,
3343
- ensureSupported: () => ensureSupported,
3344
- ensureWindows: () => ensureWindows,
3345
- equalsIgnoreCase: () => equalsIgnoreCase,
3346
- exitCodeMetadata: () => exitCodeMetadata,
3347
- exitCodes: () => exitCodes,
3348
- getBehavior: () => getBehavior,
3349
- getCountryByAlpha2: () => getCountryByAlpha2,
3350
- getCountryByAlpha3: () => getCountryByAlpha3,
3351
- getCountryByNumeric: () => getCountryByNumeric,
3352
- getExitCodeInfo: () => getExitCodeInfo,
3353
- getFallbackMetadata: () => getFallbackMetadata,
3354
- getHttpFallbackGuidance: () => getHttpFallbackGuidance,
3355
- getHttpStatus: () => getHttpStatus,
3356
- getMimeType: () => getMimeType,
3357
- getMimeTypeByExtension: () => getMimeTypeByExtension,
3358
- getPattern: () => getPattern,
3359
- getPatternRegex: () => getPatternRegex,
3360
- getPlatform: () => getPlatform,
3361
- getPlatformCapabilities: () => getPlatformCapabilities,
3362
- getSignal: () => getSignal,
3363
- getSignalCatalog: () => getSignalCatalog,
3364
- getSignalNumber: () => getSignalNumber,
3365
- getSignalPlatformCapabilities: () => getPlatformCapabilities2,
3366
- getSignalsVersion: () => getSignalsVersion,
3367
- getSimplifiedCodeDescription: () => getSimplifiedCodeDescription,
3368
- getSimplifiedCodes: () => getSimplifiedCodes,
3369
- getStatusReason: () => getStatusReason,
3370
- getWindowTimeRemaining: () => getWindowTimeRemaining,
3371
- getWindowsEvent: () => getWindowsEvent,
3372
- handleDoubleTap: () => handleDoubleTap,
3373
- handleWindowsFallback: () => handleWindowsFallback,
3374
- isClientError: () => isClientError,
3375
- isInformational: () => isInformational,
3376
- isPOSIX: () => isPOSIX,
3377
- isRedirection: () => isRedirection,
3378
- isServerError: () => isServerError,
3379
- isSignalPOSIX: () => isPOSIX2,
3380
- isSignalWindows: () => isWindows2,
3381
- isSuccess: () => isSuccess,
3382
- isSupportedMimeType: () => isSupportedMimeType,
3383
- isWindows: () => isWindows,
3384
- isWithinWindow: () => isWithinWindow,
3385
- listBehaviors: () => listBehaviors,
3386
- listCountries: () => listCountries,
3387
- listHttpStatuses: () => listHttpStatuses,
3388
- listMimeTypes: () => listMimeTypes,
3389
- listPatterns: () => listPatterns,
3390
- listSignals: () => listSignals,
3391
- loadAllCatalogs: () => loadAllCatalogs,
3392
- loadCountryCodeCatalog: () => loadCountryCodeCatalog,
3393
- loadHttpStatusCatalog: () => loadHttpStatusCatalog,
3394
- loadMimeTypeCatalog: () => loadMimeTypeCatalog,
3395
- loadPatternCatalog: () => loadPatternCatalog,
3396
- mapExitCodeToSimplified: () => mapExitCodeToSimplified,
3397
- matchMagicNumber: () => matchMagicNumber,
3398
- matchPattern: () => matchPattern,
3399
- normalize: () => normalize,
3400
- onAnyShutdown: () => onAnyShutdown,
3401
- onEmergencyQuit: () => onEmergencyQuit,
3402
- onReload: () => onReload,
3403
- onShutdown: () => onShutdown,
3404
- onUSR1: () => onUSR1,
3405
- onUSR2: () => onUSR2,
3406
- requiresFallback: () => requiresFallback,
3407
- resetDoubleTap: () => resetDoubleTap,
3408
- score: () => score,
3409
- stripAccents: () => stripAccents,
3410
- suggest: () => suggest,
3411
- supportsSignal: () => supportsSignal,
3412
- supportsSignalBasedExitCodes: () => supportsSignalExitCodes2,
3413
- supportsSignalExitCodes: () => supportsSignalExitCodes
3414
- });
3415
- var VERSION;
3416
- var init_foundry = __esm({
3417
- "src/foundry/index.ts"() {
3418
- init_country_codes();
3419
- init_errors2();
3420
- init_exit_codes();
3421
- init_http_statuses();
3422
- init_loader();
3423
- init_mime_types();
3424
- init_patterns();
3425
- init_signals();
3426
- init_similarity();
3427
- VERSION = "0.1.1";
3428
- }
3429
- });
3430
-
3431
- // src/appidentity/cache.ts
3432
- function getCachedIdentity() {
3433
- return cachedIdentity;
3434
- }
3435
- function setCachedIdentity(identity) {
3436
- cachedIdentity = identity;
3437
- }
3438
- function clearIdentityCache() {
3439
- cachedIdentity = null;
3440
- }
3441
- var cachedIdentity;
3442
- var init_cache = __esm({
3443
- "src/appidentity/cache.ts"() {
3444
- cachedIdentity = null;
3445
- }
3446
- });
3447
-
3448
- // src/appidentity/constants.ts
3449
- var APP_IDENTITY_FILENAME, APP_IDENTITY_DIR, APP_IDENTITY_ENV_VAR, APP_IDENTITY_SCHEMA_ID, MAX_ANCESTOR_SEARCH_DEPTH;
3450
- var init_constants = __esm({
3451
- "src/appidentity/constants.ts"() {
3452
- APP_IDENTITY_FILENAME = "app.yaml";
3453
- APP_IDENTITY_DIR = ".fulmen";
3454
- APP_IDENTITY_ENV_VAR = "FULMEN_APP_IDENTITY_PATH";
3455
- APP_IDENTITY_SCHEMA_ID = "config/repository/app-identity/v1.0.0/app-identity";
3456
- MAX_ANCESTOR_SEARCH_DEPTH = 20;
3457
- }
3458
- });
3459
- var init_correlation = __esm({
3460
- "src/errors/correlation.ts"() {
3461
- }
3462
- });
3463
-
3464
- // src/errors/severity.ts
3465
- function getDefaultSeverity() {
3466
- return {
3467
- name: Severity.MEDIUM,
3468
- level: 2
3469
- };
3470
- }
3471
- var Severity, SEVERITY_LEVELS;
3472
- var init_severity = __esm({
3473
- "src/errors/severity.ts"() {
3474
- Severity = {
3475
- INFO: "info",
3476
- LOW: "low",
3477
- MEDIUM: "medium",
3478
- HIGH: "high",
3479
- CRITICAL: "critical"
3480
- };
3481
- SEVERITY_LEVELS = {
3482
- info: 0,
3483
- low: 1,
3484
- medium: 2,
3485
- high: 3,
3486
- critical: 4
3487
- };
3488
- }
3489
- });
3490
-
3491
- // src/errors/serialization.ts
3492
- function extractErrorMessage(error) {
3493
- if (error instanceof Error) {
3494
- return error.message;
3495
- }
3496
- if (isErrorLike(error)) {
3497
- return error.message;
3498
- }
3499
- if (typeof error === "string") {
3500
- return error;
3501
- }
3502
- return String(error);
3503
- }
3504
- function extractStackTrace(error) {
3505
- if (error instanceof Error) {
3506
- return error.stack;
3507
- }
3508
- if (isErrorLike(error) && typeof error.stack === "string") {
3509
- return error.stack;
3510
- }
3511
- return void 0;
3512
- }
3513
- function isErrorLike(value) {
3514
- return typeof value === "object" && value !== null && "message" in value && typeof value.message === "string";
3515
- }
3516
- var init_serialization = __esm({
3517
- "src/errors/serialization.ts"() {
3518
- init_severity();
3519
- }
3520
- });
3521
-
3522
- // src/errors/validators.ts
3523
- async function validateErrorData(data) {
3524
- return ErrorValidator.getInstance().validate(data);
3525
- }
3526
- var ErrorValidator;
3527
- var init_validators = __esm({
3528
- "src/errors/validators.ts"() {
3529
- init_schema();
3530
- ErrorValidator = class _ErrorValidator {
3531
- static instance;
3532
- validateFn = null;
3533
- initPromise = null;
3534
- initError = null;
3535
- constructor() {
3536
- }
3537
- /**
3538
- * Get singleton instance
3539
- */
3540
- static getInstance() {
3541
- if (!_ErrorValidator.instance) {
3542
- _ErrorValidator.instance = new _ErrorValidator();
3543
- }
3544
- return _ErrorValidator.instance;
3545
- }
3546
- /**
3547
- * Initialize validator (lazy load, async)
3548
- */
3549
- async init() {
3550
- if (this.validateFn !== null || this.initError !== null) {
3551
- return;
3552
- }
3553
- if (this.initPromise) {
3554
- return this.initPromise;
3555
- }
3556
- this.initPromise = (async () => {
3557
- try {
3558
- await compileSchemaById("pathfinder/v1.0.0/error-response");
3559
- await compileSchemaById("assessment/v1.0.0/severity-definitions");
3560
- this.validateFn = await compileSchemaById("error-handling/v1.0.0/error-response");
3561
- } catch (err) {
3562
- this.initError = err instanceof Error ? err : new Error(String(err));
3563
- throw new Error(`Failed to initialize error validator: ${this.initError.message}`);
3564
- }
3565
- })();
3566
- return this.initPromise;
3567
- }
3568
- /**
3569
- * Validate error data against schema
3570
- *
3571
- * @param data - Data to validate
3572
- * @returns Promise resolving to true if valid, false otherwise
3573
- * @throws {Error} If validator failed to initialize
3574
- */
3575
- async validate(data) {
3576
- if (this.validateFn === null) {
3577
- await this.init();
3578
- }
3579
- if (this.initError) {
3580
- throw this.initError;
3581
- }
3582
- if (!this.validateFn) {
3583
- throw new Error("Validator not initialized");
3584
- }
3585
- return this.validateFn(data);
3586
- }
3587
- /**
3588
- * Get validation errors from last validation
3589
- *
3590
- * @returns Validation errors or null
3591
- */
3592
- getErrors() {
3593
- if (!this.validateFn) {
3594
- return null;
3595
- }
3596
- return this.validateFn.errors;
3597
- }
3598
- /**
3599
- * Reset validator state (for testing)
3600
- * @internal
3601
- */
3602
- static _reset() {
3603
- _ErrorValidator.instance = new _ErrorValidator();
3604
- }
3605
- };
3606
- }
3607
- });
3608
-
3609
- // src/errors/fulmen-error.ts
3610
- function isFulmenErrorData(value) {
3611
- return typeof value === "object" && value !== null && "code" in value && typeof value.code === "string" && "message" in value && typeof value.message === "string";
3612
- }
3613
- var FulmenError;
3614
- var init_fulmen_error = __esm({
3615
- "src/errors/fulmen-error.ts"() {
3616
- init_serialization();
3617
- init_severity();
3618
- init_validators();
3619
- FulmenError = class _FulmenError extends Error {
3620
- data;
3621
- constructor(data) {
3622
- super(data.message);
3623
- this.name = "FulmenError";
3624
- this.data = Object.freeze({ ...data });
3625
- Error.captureStackTrace(this, _FulmenError);
3626
- }
3627
- /**
3628
- * Serialize to JSON (schema-compliant)
3629
- */
3630
- toJSON() {
3631
- return this.data;
3632
- }
3633
- /**
3634
- * Check equality with another FulmenError
3635
- */
3636
- equals(other) {
3637
- return JSON.stringify(this.data) === JSON.stringify(other.data);
3638
- }
3639
- /**
3640
- * Get severity level for comparison
3641
- */
3642
- getSeverityLevel() {
3643
- return this.data.severity_level ?? SEVERITY_LEVELS[this.data.severity ?? "medium"];
3644
- }
3645
- /**
3646
- * Wrap an existing error with FulmenError structure
3647
- *
3648
- * @param error - Error to wrap (Error instance or FulmenErrorData)
3649
- * @param options - Additional error options
3650
- * @returns New FulmenError instance
3651
- *
3652
- * @example
3653
- * ```typescript
3654
- * try {
3655
- * throw new Error('Config invalid');
3656
- * } catch (err) {
3657
- * const fulmenErr = FulmenError.wrap(err, {
3658
- * code: 'CONFIG_INVALID',
3659
- * severity: 'high',
3660
- * exit_code: 2
3661
- * });
3662
- * throw fulmenErr;
3663
- * }
3664
- * ```
3665
- */
3666
- static wrap(error, options = {}) {
3667
- if (error instanceof _FulmenError) {
3668
- const effectiveSeverity = options.severity ?? error.data.severity ?? Severity.MEDIUM;
3669
- const effectiveSeverityLevel = SEVERITY_LEVELS[effectiveSeverity];
3670
- const timestamp = (/* @__PURE__ */ new Date()).toISOString();
3671
- return new _FulmenError({
3672
- ...error.data,
3673
- ...options,
3674
- code: options.code ?? error.data.code,
3675
- message: error.data.message,
3676
- severity: effectiveSeverity,
3677
- // Consistent severity
3678
- severity_level: effectiveSeverityLevel,
3679
- // Recomputed level
3680
- timestamp
3681
- // Updated timestamp
3682
- });
3683
- }
3684
- if (isFulmenErrorData(error)) {
3685
- const defaultSeverity = getDefaultSeverity();
3686
- const effectiveSeverity = options.severity ?? error.severity ?? defaultSeverity.name;
3687
- const effectiveSeverityLevel = SEVERITY_LEVELS[effectiveSeverity];
3688
- return new _FulmenError({
3689
- ...error,
3690
- ...options,
3691
- severity: effectiveSeverity,
3692
- severity_level: effectiveSeverityLevel,
3693
- // Recomputed, not from error.severity_level
3694
- timestamp: error.timestamp ?? (/* @__PURE__ */ new Date()).toISOString()
3695
- });
3696
- }
3697
- return _FulmenError.fromError(error, options);
3698
- }
3699
- /**
3700
- * Create FulmenError from native Error object
3701
- *
3702
- * @param err - Native Error instance
3703
- * @param options - Error options
3704
- * @returns New FulmenError instance
3705
- *
3706
- * @example
3707
- * ```typescript
3708
- * const err = new TypeError('Invalid type');
3709
- * const fulmenErr = FulmenError.fromError(err, {
3710
- * code: 'TYPE_ERROR',
3711
- * severity: 'medium'
3712
- * });
3713
- * ```
3714
- */
3715
- static fromError(err, options = {}) {
3716
- const code = options.code ?? "UNKNOWN_ERROR";
3717
- const severity = options.severity ?? Severity.MEDIUM;
3718
- const severityLevel = SEVERITY_LEVELS[severity];
3719
- const message = extractErrorMessage(err);
3720
- const stack = extractStackTrace(err);
3721
- const data = {
3722
- code,
3723
- message,
3724
- severity,
3725
- severity_level: severityLevel,
3726
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3727
- ...options,
3728
- context: {
3729
- ...options.context,
3730
- originalName: err instanceof Error ? err.name : typeof err,
3731
- stack
3732
- },
3733
- original: stack || message
3734
- };
3735
- return new _FulmenError(data);
3736
- }
3737
- /**
3738
- * Validate error data against schema
3739
- *
3740
- * @param data - Error data to validate
3741
- * @returns Promise resolving to true if valid
3742
- *
3743
- * @example
3744
- * ```typescript
3745
- * const data = { code: 'TEST', message: 'Test error' };
3746
- * if (await FulmenError.validate(data)) {
3747
- * const err = new FulmenError(data);
3748
- * }
3749
- * ```
3750
- */
3751
- static async validate(data) {
3752
- return validateErrorData(data);
3753
- }
3754
- /**
3755
- * Exit process with structured error
3756
- *
3757
- * Logs error as JSON and exits with specified exit code.
3758
- * Mockable for testing (override process.exit).
3759
- *
3760
- * @param error - FulmenError instance
3761
- * @param options - Exit options
3762
- *
3763
- * @example
3764
- * ```typescript
3765
- * const err = FulmenError.fromError(new Error('Fatal'), {
3766
- * code: 'FATAL_ERROR',
3767
- * exit_code: 1
3768
- * });
3769
- * FulmenError.exitWithError(err); // Exits with code 1
3770
- * ```
3771
- */
3772
- static exitWithError(error, options = {}) {
3773
- const logger = options.logger ?? console.error;
3774
- const exitCode = error.data.exit_code ?? 1;
3775
- logger(JSON.stringify(error.toJSON(), null, 2));
3776
- process.exit(exitCode);
3777
- }
3778
- };
3779
- }
3780
- });
3781
-
3782
- // src/errors/index.ts
3783
- var init_errors4 = __esm({
3784
- "src/errors/index.ts"() {
3785
- init_correlation();
3786
- init_fulmen_error();
3787
- init_serialization();
3788
- init_severity();
3789
- init_validators();
3790
- }
3791
- });
3792
-
3793
- // src/appidentity/errors.ts
3794
- var errors_exports2 = {};
3795
- __export(errors_exports2, {
3796
- AppIdentityError: () => AppIdentityError
3797
- });
3798
- var AppIdentityError;
3799
- var init_errors5 = __esm({
3800
- "src/appidentity/errors.ts"() {
3801
- init_errors4();
3802
- AppIdentityError = class _AppIdentityError extends FulmenError {
3803
- identityPath;
3804
- constructor(message, identityPath, cause) {
3805
- let errorData;
3806
- if (cause) {
3807
- errorData = FulmenError.fromError(cause, {
3808
- code: "APP_IDENTITY_ERROR",
3809
- severity: "high",
3810
- context: { identityPath }
3811
- }).data;
3812
- } else {
3813
- errorData = {
3814
- code: "APP_IDENTITY_ERROR",
3815
- message,
3816
- severity: "high",
3817
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
3818
- context: { identityPath }
3819
- };
3820
- }
3821
- super(errorData);
3822
- this.name = "AppIdentityError";
3823
- this.identityPath = identityPath;
3824
- if (Error.captureStackTrace) {
3825
- Error.captureStackTrace(this, _AppIdentityError);
3826
- }
3827
- }
3828
- /**
3829
- * Create error for identity not found
3830
- */
3831
- static notFound(searchedPaths) {
3832
- const message = `App identity not found
3833
- Searched paths:
3834
- ${searchedPaths.map((p) => ` - ${p}`).join("\n")}`;
3835
- return new _AppIdentityError(message);
3836
- }
3837
- /**
3838
- * Create error for schema validation failure
3839
- */
3840
- static validationFailed(path, diagnostics) {
3841
- const errorCount = diagnostics.filter((d) => d.severity === "ERROR").length;
3842
- const warningCount = diagnostics.filter((d) => d.severity === "WARN").length;
3843
- let message = `Invalid app identity: ${path}
3844
- `;
3845
- message += `Validation errors: ${errorCount} error(s), ${warningCount} warning(s)
3846
- `;
3847
- const displayDiagnostics = diagnostics.slice(0, 3);
3848
- for (const diag of displayDiagnostics) {
3849
- message += ` - ${diag.message}`;
3850
- if (diag.pointer) {
3851
- message += ` at ${diag.pointer}`;
3852
- }
3853
- message += "\n";
3854
- }
3855
- if (diagnostics.length > 3) {
3856
- message += ` ... and ${diagnostics.length - 3} more
3857
- `;
3858
- }
3859
- return new _AppIdentityError(message, path);
3860
- }
3861
- /**
3862
- * Create error for environment variable override pointing to missing file
3863
- */
3864
- static envOverrideMissing(envPath) {
3865
- const message = `FULMEN_APP_IDENTITY_PATH points to missing file: ${envPath}
3866
- `;
3867
- return new _AppIdentityError(message, envPath);
3868
- }
3869
- /**
3870
- * Create error for YAML parsing failure
3871
- */
3872
- static parseFailed(path, cause) {
3873
- const message = `Failed to parse identity file: ${path}
3874
- ${cause.message}`;
3875
- return new _AppIdentityError(message, path, cause);
3876
- }
3877
- /**
3878
- * Create error for file read failure
3879
- */
3880
- static readFailed(path, cause) {
3881
- const message = `Failed to read identity file: ${path}
3882
- ${cause.message}`;
3883
- return new _AppIdentityError(message, path, cause);
3884
- }
3885
- /**
3886
- * Create error for embedded identity already registered
3887
- *
3888
- * Uses first-wins semantics - once registered, cannot be replaced
3889
- */
3890
- static alreadyRegistered() {
3891
- const message = "Embedded identity already registered. Registration uses first-wins semantics and cannot be replaced.";
3892
- return new _AppIdentityError(message);
3893
- }
3894
- /**
3895
- * Create error for embedded identity YAML parsing failure
3896
- */
3897
- static embeddedParseFailed(cause) {
3898
- const message = `Failed to parse embedded identity YAML: ${cause.message}`;
3899
- return new _AppIdentityError(message, void 0, cause);
3900
- }
3901
- /**
3902
- * Create error for embedded identity schema validation failure
3903
- */
3904
- static embeddedValidationFailed(diagnostics) {
3905
- const errorCount = diagnostics.filter((d) => d.severity === "ERROR").length;
3906
- const warningCount = diagnostics.filter((d) => d.severity === "WARN").length;
3907
- let message = "Invalid embedded identity\n";
3908
- message += `Validation errors: ${errorCount} error(s), ${warningCount} warning(s)
3909
- `;
3910
- const displayDiagnostics = diagnostics.slice(0, 3);
3911
- for (const diag of displayDiagnostics) {
3912
- message += ` - ${diag.message}`;
3913
- if (diag.pointer) {
3914
- message += ` at ${diag.pointer}`;
3915
- }
3916
- message += "\n";
3917
- }
3918
- if (diagnostics.length > 3) {
3919
- message += ` ... and ${diagnostics.length - 3} more
3920
- `;
3921
- }
3922
- return new _AppIdentityError(message);
3923
- }
3924
- };
3925
- }
3926
- });
3927
- async function discoverIdentityPath(options) {
3928
- if (options?.path) {
3929
- const exists = await fileExists(options.path);
3930
- if (!exists) {
3931
- throw AppIdentityError.notFound([options.path]);
3932
- }
3933
- return { path: options.path, source: "explicit" };
3934
- }
3935
- const envPath = process.env[APP_IDENTITY_ENV_VAR];
3936
- if (envPath) {
3937
- const exists = await fileExists(envPath);
3938
- if (!exists) {
3939
- throw AppIdentityError.envOverrideMissing(envPath);
3940
- }
3941
- return { path: envPath, source: "env" };
3942
- }
3943
- const startDir = options?.startDir || process.cwd();
3944
- const result = await searchAncestors(startDir);
3945
- if (result) {
3946
- return { path: result, source: "ancestor" };
3947
- }
3948
- return null;
3949
- }
3950
- async function searchAncestors(startDir) {
3951
- let currentDir = startDir;
3952
- const searchedPaths = [];
3953
- for (let i = 0; i < MAX_ANCESTOR_SEARCH_DEPTH; i++) {
3954
- const candidatePath = join(currentDir, APP_IDENTITY_DIR, APP_IDENTITY_FILENAME);
3955
- searchedPaths.push(candidatePath);
3956
- if (await fileExists(candidatePath)) {
3957
- return candidatePath;
3958
- }
3959
- const parentDir = dirname(currentDir);
3960
- if (parentDir === currentDir) {
3961
- throw AppIdentityError.notFound(searchedPaths);
3962
- }
3963
- currentDir = parentDir;
3964
- }
3965
- throw AppIdentityError.notFound(searchedPaths);
3966
- }
3967
- async function fileExists(path) {
3968
- try {
3969
- await access(path);
3970
- return true;
3971
- } catch {
3972
- return false;
3973
- }
3974
- }
3975
- var init_discovery = __esm({
3976
- "src/appidentity/discovery.ts"() {
3977
- init_constants();
3978
- init_errors5();
3979
- }
3980
- });
3981
- function getEmbeddedIdentity() {
3982
- return embeddedIdentity;
3983
- }
3984
- var embeddedIdentity;
3985
- var init_embedded = __esm({
3986
- "src/appidentity/embedded.ts"() {
3987
- init_schema();
3988
- init_constants();
3989
- init_errors5();
3990
- embeddedIdentity = null;
3991
- }
3992
- });
3993
-
3994
- // src/appidentity/loader.ts
3995
- var loader_exports = {};
3996
- __export(loader_exports, {
3997
- clearIdentityCache: () => clearIdentityCache,
3998
- getCachedIdentity: () => getCachedIdentity,
3999
- loadIdentity: () => loadIdentity
4000
- });
4001
- function deepFreeze5(obj) {
4002
- Object.freeze(obj);
4003
- Object.getOwnPropertyNames(obj).forEach((prop) => {
4004
- const value = obj[prop];
4005
- if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
4006
- deepFreeze5(value);
4007
- }
4008
- });
4009
- return obj;
4010
- }
4011
- async function loadIdentity(options) {
4012
- if (options?.identity) {
4013
- return deepFreeze5(structuredClone(options.identity));
4014
- }
4015
- if (!options?.skipCache) {
4016
- const cached = getCachedIdentity();
4017
- if (cached) {
4018
- return cached;
4019
- }
4020
- }
4021
- let discovery;
4022
- try {
4023
- discovery = await discoverIdentityPath({
4024
- path: options?.path,
4025
- startDir: options?.startDir
4026
- });
4027
- } catch (error) {
4028
- const hasExplicitPath = Boolean(options?.path);
4029
- const hasEnvOverride = Boolean(process.env[APP_IDENTITY_ENV_VAR]);
4030
- if (!hasExplicitPath && !hasEnvOverride && error instanceof AppIdentityError) {
4031
- const embedded = getEmbeddedIdentity();
4032
- if (embedded) {
4033
- setCachedIdentity(embedded);
4034
- return embedded;
4035
- }
4036
- }
4037
- throw error;
4038
- }
4039
- if (!discovery) {
4040
- const embedded = getEmbeddedIdentity();
4041
- if (embedded) {
4042
- setCachedIdentity(embedded);
4043
- return embedded;
4044
- }
4045
- throw AppIdentityError.notFound([]);
4046
- }
4047
- let content;
4048
- try {
4049
- content = await readFile(discovery.path, "utf-8");
4050
- } catch (error) {
4051
- throw AppIdentityError.readFailed(
4052
- discovery.path,
4053
- error instanceof Error ? error : new Error(String(error))
4054
- );
4055
- }
4056
- let parsed;
4057
- try {
4058
- parsed = parse(content);
4059
- } catch (error) {
4060
- throw AppIdentityError.parseFailed(
4061
- discovery.path,
4062
- error instanceof Error ? error : new Error(String(error))
4063
- );
4064
- }
4065
- if (!options?.skipValidation) {
4066
- const result = await validateDataBySchemaId(parsed, APP_IDENTITY_SCHEMA_ID);
4067
- if (!result.valid) {
4068
- throw AppIdentityError.validationFailed(discovery.path, result.diagnostics);
4069
- }
4070
- }
4071
- const identity = deepFreeze5(structuredClone(parsed));
4072
- setCachedIdentity(identity);
4073
- return identity;
4074
- }
4075
- var init_loader2 = __esm({
4076
- "src/appidentity/loader.ts"() {
4077
- init_schema();
4078
- init_cache();
4079
- init_constants();
4080
- init_discovery();
4081
- init_embedded();
4082
- init_errors5();
4083
- }
4084
- });
4085
- function createCLI(options = {}) {
4086
- const program = new Command();
4087
- program.name("tsfulmen-schema").description("Schema validation and discovery CLI for Fulmen (developer tool)").version("0.1.0");
4088
- program.command("list").description("List available schemas from registry").argument("[prefix]", "Filter schemas by prefix").option("--base-dir <path>", "Override schema base directory").action(async (prefix, cmdOptions) => {
4089
- try {
4090
- const schemas = await listSchemas(prefix, {
4091
- baseDir: cmdOptions?.baseDir || options.baseDir
4092
- });
4093
- if (schemas.length === 0) {
4094
- console.log("No schemas found");
4095
- return;
4096
- }
4097
- console.log(`Found ${schemas.length} schema(s):
4098
- `);
4099
- for (const schema of schemas) {
4100
- console.log(` ${schema.id}`);
4101
- console.log(` Format: ${schema.format}`);
4102
- console.log(` Path: ${schema.relativePath}`);
4103
- if (schema.description) {
4104
- console.log(` Description: ${schema.description}`);
4105
- }
4106
- console.log();
4107
- }
4108
- } catch (error) {
4109
- console.error("Error listing schemas:", error.message);
4110
- process.exit(1);
4111
- }
4112
- });
4113
- program.command("show").description("Show schema details").requiredOption("--schema-id <id>", "Schema ID to show").option("--base-dir <path>", "Override schema base directory").action(async (cmdOptions) => {
4114
- try {
4115
- const registry = getSchemaRegistry({
4116
- baseDir: cmdOptions.baseDir || options.baseDir
4117
- });
4118
- const schema = await registry.getSchema(cmdOptions.schemaId);
4119
- console.log("Schema Details:\n");
4120
- console.log(` ID: ${schema.id}`);
4121
- console.log(` Format: ${schema.format}`);
4122
- console.log(` Path: ${schema.path}`);
4123
- console.log(` Relative Path: ${schema.relativePath}`);
4124
- if (schema.version) {
4125
- console.log(` Version: ${schema.version}`);
4126
- }
4127
- if (schema.description) {
4128
- console.log(` Description: ${schema.description}`);
4129
- }
4130
- if (schema.schemaDraft) {
4131
- console.log(` Schema Draft: ${schema.schemaDraft}`);
4132
- }
4133
- const content = await readFile(schema.path, "utf-8");
4134
- console.log("\nSchema Content:");
4135
- console.log(content);
4136
- } catch (error) {
4137
- console.error("Error showing schema:", error.message);
4138
- process.exit(1);
4139
- }
4140
- });
4141
- program.command("validate").description("Validate data file against schema").requiredOption("--schema-id <id>", "Schema ID to validate against").argument("<file>", "Data file to validate").option("--use-goneat", "Use goneat for validation (requires goneat binary)").option("--goneat-path <path>", "Path to goneat binary").option("--base-dir <path>", "Override schema base directory").action(
4142
- async (file, cmdOptions) => {
4143
- try {
4144
- let result;
4145
- if (cmdOptions.useGoneat) {
4146
- const available = await isGoneatAvailable(cmdOptions.goneatPath);
4147
- if (!available) {
4148
- console.error("\u274C goneat not available. Install goneat or remove --use-goneat flag.");
4149
- console.error(" AJV validation (default) works without external dependencies.");
4150
- process.exit(1);
4151
- }
4152
- const registry = getSchemaRegistry({
4153
- baseDir: cmdOptions.baseDir || options.baseDir
4154
- });
4155
- const schema = await registry.getSchema(cmdOptions.schemaId);
4156
- console.log("Using goneat validation...");
4157
- result = await runGoneatValidation(schema.path, file, cmdOptions.goneatPath);
4158
- } else {
4159
- console.log("Using AJV validation...");
4160
- result = await validateFileBySchemaId(file, cmdOptions.schemaId, {
4161
- baseDir: cmdOptions.baseDir || options.baseDir
4162
- });
4163
- }
4164
- if (result.valid) {
4165
- console.log(`\u2705 Validation passed (${result.source})`);
4166
- process.exit(0);
4167
- } else {
4168
- console.log(`\u274C Validation failed (${result.source})`);
4169
- console.log("\nDiagnostics:");
4170
- console.log(formatDiagnostics(result.diagnostics));
4171
- process.exit(1);
4172
- }
4173
- } catch (error) {
4174
- console.error("Error validating file:", error.message);
4175
- process.exit(1);
4176
- }
4177
- }
4178
- );
4179
- program.command("validate-schema").description("Validate a schema file itself").argument("<file>", "Schema file to validate").action(async (file) => {
4180
- try {
4181
- const content = await readFile(file, "utf-8");
4182
- const { validateSchema: validateSchema2 } = await Promise.resolve().then(() => (init_validator(), validator_exports));
4183
- const result = await validateSchema2(content);
4184
- if (result.valid) {
4185
- console.log("\u2705 Schema is valid");
4186
- process.exit(0);
4187
- } else {
4188
- console.log("\u274C Schema is invalid");
4189
- console.log("\nDiagnostics:");
4190
- console.log(formatDiagnostics(result.diagnostics));
4191
- process.exit(1);
4192
- }
4193
- } catch (error) {
4194
- console.error("Error validating schema:", error.message);
4195
- process.exit(1);
4196
- }
4197
- });
4198
- program.command("normalize").description("Normalize schema to canonical JSON format").argument("<file>", "Schema file to normalize").option("--compact", "Output compact JSON (no formatting)").option("-o, --output <file>", "Write to output file instead of stdout").action(async (file, cmdOptions) => {
4199
- try {
4200
- const content = await readFile(file, "utf-8");
4201
- const normalized = normalizeSchema(content, {
4202
- compact: cmdOptions.compact
4203
- });
4204
- if (cmdOptions.output) {
4205
- await writeFile(cmdOptions.output, normalized, "utf-8");
4206
- console.log(`\u2705 Normalized schema written to ${cmdOptions.output}`);
4207
- } else {
4208
- console.log(normalized);
4209
- }
4210
- } catch (error) {
4211
- console.error("Error normalizing schema:", error.message);
4212
- process.exit(1);
4213
- }
4214
- });
4215
- program.command("compare").description("Compare two schemas for semantic equality").argument("<file1>", "First schema file").argument("<file2>", "Second schema file").option("--show-normalized", "Show normalized outputs").action(async (file1, file2, cmdOptions) => {
4216
- try {
4217
- const content1 = await readFile(file1, "utf-8");
4218
- const content2 = await readFile(file2, "utf-8");
4219
- const result = compareSchemas(content1, content2);
4220
- if (result.equal) {
4221
- console.log("\u2705 Schemas are semantically equal");
4222
- } else {
4223
- console.log("\u274C Schemas differ");
4224
- }
4225
- if (cmdOptions.showNormalized) {
4226
- console.log("\nNormalized Schema 1:");
4227
- console.log(result.normalizedA);
4228
- console.log("\nNormalized Schema 2:");
4229
- console.log(result.normalizedB);
4230
- }
4231
- process.exit(result.equal ? 0 : 1);
4232
- } catch (error) {
4233
- console.error("Error comparing schemas:", error.message);
4234
- process.exit(1);
4235
- }
4236
- });
4237
- program.command("export").description("Export schema from registry to file with provenance").requiredOption("--schema-id <id>", "Schema ID to export").requiredOption("--out <path>", "Output file path").option("--force", "Overwrite existing file", false).option("--no-provenance", "Exclude provenance metadata").option("--no-validate", "Skip schema validation before export").option("--format <format>", "Export format (json|yaml|auto)", "auto").option("--base-dir <path>", "Override schema base directory").action(
4238
- async (cmdOptions) => {
4239
- try {
4240
- const { exportSchema: exportSchema2 } = await Promise.resolve().then(() => (init_export(), export_exports));
4241
- const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
4242
- const result = await exportSchema2({
4243
- schemaId: cmdOptions.schemaId,
4244
- outPath: cmdOptions.out,
4245
- includeProvenance: cmdOptions.provenance ?? true,
4246
- validate: cmdOptions.validate ?? true,
4247
- overwrite: cmdOptions.force ?? false,
4248
- format: cmdOptions.format ?? "auto",
4249
- baseDir: cmdOptions.baseDir || options.baseDir
4250
- });
4251
- console.log("\u2705 Schema exported successfully");
4252
- console.log(` Schema ID: ${result.schemaId}`);
4253
- console.log(` Output: ${result.outPath}`);
4254
- console.log(` Format: ${result.format}`);
4255
- if (result.provenance) {
4256
- console.log("\nProvenance:");
4257
- console.log(` Crucible: ${result.provenance.crucible_version}`);
4258
- console.log(` Library: ${result.provenance.library_version}`);
4259
- if (result.provenance.revision) {
4260
- console.log(` Revision: ${result.provenance.revision}`);
4261
- }
4262
- console.log(` Exported: ${result.provenance.exported_at}`);
4263
- }
4264
- process.exit(exitCodes2.EXIT_SUCCESS);
4265
- } catch (error) {
4266
- const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
4267
- const { SchemaExportError: SchemaExportError2, SchemaValidationError: SchemaValidationError2, ExportErrorReason: ExportErrorReason2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
4268
- console.error("\u274C Schema export failed:", error.message);
4269
- if (error instanceof SchemaExportError2) {
4270
- if (error.outPath) {
4271
- console.error(` Output path: ${error.outPath}`);
4272
- }
4273
- switch (error.reason) {
4274
- case ExportErrorReason2.FILE_EXISTS:
4275
- case ExportErrorReason2.WRITE_FAILED:
4276
- process.exit(exitCodes2.EXIT_FILE_WRITE_ERROR);
4277
- break;
4278
- case ExportErrorReason2.INVALID_FORMAT:
4279
- process.exit(exitCodes2.EXIT_INVALID_ARGUMENT);
4280
- break;
4281
- default:
4282
- process.exit(exitCodes2.EXIT_FAILURE);
4283
- }
972
+ return "json";
4284
973
  }
4285
- if (error instanceof SchemaValidationError2) {
4286
- const errorMsg = error.message.toLowerCase();
4287
- if (errorMsg.includes("not found")) {
4288
- process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
974
+ }
975
+ /**
976
+ * Extract metadata from schema file
977
+ */
978
+ async extractMetadata(filePath) {
979
+ try {
980
+ const content = await readFile(filePath, "utf-8");
981
+ const format = this.getSchemaFormat(filePath);
982
+ let parsed;
983
+ if (format === "yaml") {
984
+ parsed = parse(content);
985
+ } else {
986
+ parsed = JSON.parse(content);
4289
987
  }
4290
- process.exit(exitCodes2.EXIT_DATA_INVALID);
988
+ const baseDir = this.options.baseDir ?? "";
989
+ const relativePath = relative(baseDir, filePath);
990
+ return {
991
+ id: this.buildSchemaId(filePath, baseDir),
992
+ path: filePath,
993
+ relativePath,
994
+ format,
995
+ version: parsed.$schema || parsed.version,
996
+ description: parsed.title || parsed.description,
997
+ schemaDraft: parsed.$schema
998
+ };
999
+ } catch (error) {
1000
+ throw SchemaValidationError.registryError(
1001
+ "metadata extraction",
1002
+ `Failed to process ${filePath}: ${error.message}`
1003
+ );
4291
1004
  }
4292
- process.exit(exitCodes2.EXIT_FAILURE);
4293
1005
  }
4294
- }
4295
- );
4296
- program.command("identity-show").description("Show application identity from .fulmen/app.yaml").option("--path <path>", "Explicit path to app.yaml").option("--json", "Output as JSON").action(async (cmdOptions) => {
4297
- try {
4298
- const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
4299
- const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
4300
- const identity = await loadIdentity2({ path: cmdOptions.path });
4301
- if (cmdOptions.json) {
4302
- console.log(JSON.stringify(identity, null, 2));
4303
- } else {
4304
- console.log("Application Identity:\n");
4305
- console.log(` Binary Name: ${identity.app.binary_name}`);
4306
- console.log(` Vendor: ${identity.app.vendor}`);
4307
- console.log(` Env Prefix: ${identity.app.env_prefix}`);
4308
- console.log(` Config Name: ${identity.app.config_name}`);
4309
- console.log(` Description: ${identity.app.description}`);
4310
- if (identity.metadata) {
4311
- console.log("\nMetadata:");
4312
- if (identity.metadata.license) {
4313
- console.log(` License: ${identity.metadata.license}`);
4314
- }
4315
- if (identity.metadata.repository_category) {
4316
- console.log(` Category: ${identity.metadata.repository_category}`);
1006
+ /**
1007
+ * Discover and index all available schemas
1008
+ */
1009
+ async discoverSchemas() {
1010
+ try {
1011
+ const baseDir = this.options.baseDir ?? "";
1012
+ const patterns = this.options.patterns ?? [];
1013
+ if (patterns.length === 0) {
1014
+ this.schemas.clear();
1015
+ return;
4317
1016
  }
4318
- if (identity.metadata.telemetry_namespace) {
4319
- console.log(` Telemetry: ${identity.metadata.telemetry_namespace}`);
1017
+ const pattern = patterns.map((p) => join(baseDir, p));
1018
+ try {
1019
+ await access(baseDir);
1020
+ } catch {
1021
+ this.schemas.clear();
1022
+ return;
4320
1023
  }
4321
- if (identity.metadata.project_url) {
4322
- console.log(` Project URL: ${identity.metadata.project_url}`);
1024
+ const files = await glob(pattern, {
1025
+ absolute: true,
1026
+ followSymbolicLinks: this.options.followSymlinks,
1027
+ deep: this.options.maxDepth,
1028
+ onlyFiles: true,
1029
+ suppressErrors: true
1030
+ // Don't throw on permission errors
1031
+ });
1032
+ this.schemas.clear();
1033
+ for (const filePath of files) {
1034
+ try {
1035
+ const metadata = await this.extractMetadata(filePath);
1036
+ this.schemas.set(metadata.id, metadata);
1037
+ } catch (error) {
1038
+ console.warn(`Warning: Failed to process schema ${filePath}:`, error);
1039
+ }
4323
1040
  }
1041
+ } catch (error) {
1042
+ throw SchemaValidationError.registryError("discovery", error.message);
4324
1043
  }
4325
1044
  }
4326
- process.exit(exitCodes2.EXIT_SUCCESS);
4327
- } catch (error) {
4328
- const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
4329
- const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
4330
- console.error("\u274C Failed to load identity:", error.message);
4331
- if (error instanceof AppIdentityError2) {
4332
- if (error.message.includes("not found")) {
4333
- process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
1045
+ /**
1046
+ * List available schemas with optional prefix filtering
1047
+ */
1048
+ async listSchemas(prefix) {
1049
+ if (this.schemas.size === 0) {
1050
+ await this.discoverSchemas();
4334
1051
  }
4335
- if (error.message.includes("Invalid") || error.message.includes("validation")) {
4336
- process.exit(exitCodes2.EXIT_DATA_INVALID);
1052
+ const schemas = Array.from(this.schemas.values());
1053
+ if (prefix) {
1054
+ return schemas.filter((schema) => schema.id.startsWith(prefix));
4337
1055
  }
1056
+ return schemas;
4338
1057
  }
4339
- process.exit(exitCodes2.EXIT_FAILURE);
4340
- }
4341
- });
4342
- program.command("identity-validate").description("Validate application identity against schema").argument("[file]", "Path to app.yaml (defaults to discovery)").action(async (file) => {
4343
- try {
4344
- const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
4345
- const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
4346
- console.log("Validating application identity...");
4347
- const identity = await loadIdentity2({ path: file });
4348
- console.log("\u2705 Identity is valid");
4349
- console.log(` Binary: ${identity.app.binary_name}`);
4350
- console.log(` Vendor: ${identity.app.vendor}`);
4351
- process.exit(exitCodes2.EXIT_SUCCESS);
4352
- } catch (error) {
4353
- const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
4354
- const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
4355
- console.error("\u274C Identity validation failed:", error.message);
4356
- if (error instanceof AppIdentityError2) {
4357
- if (error.message.includes("not found")) {
4358
- process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
1058
+ /**
1059
+ * Get schema by logical ID
1060
+ */
1061
+ async getSchema(id) {
1062
+ if (this.schemas.size === 0) {
1063
+ await this.discoverSchemas();
4359
1064
  }
4360
- if (error.message.includes("Invalid") || error.message.includes("validation")) {
4361
- process.exit(exitCodes2.EXIT_DATA_INVALID);
1065
+ const schema = this.schemas.get(id);
1066
+ if (!schema) {
1067
+ throw SchemaValidationError.schemaNotFound(id);
4362
1068
  }
1069
+ return schema;
4363
1070
  }
4364
- process.exit(exitCodes2.EXIT_FAILURE);
4365
- }
4366
- });
4367
- return program;
4368
- }
1071
+ /**
1072
+ * Get schema by file path
1073
+ */
1074
+ async getSchemaByPath(filePath) {
1075
+ if (this.schemas.size === 0) {
1076
+ await this.discoverSchemas();
1077
+ }
1078
+ const absolutePath = filePath.startsWith("/") ? filePath : join(process.cwd(), filePath);
1079
+ for (const schema of this.schemas.values()) {
1080
+ if (schema.path === absolutePath) {
1081
+ return schema;
1082
+ }
1083
+ }
1084
+ throw SchemaValidationError.schemaNotFound(filePath);
1085
+ }
1086
+ /**
1087
+ * Check if schema exists
1088
+ */
1089
+ async hasSchema(id) {
1090
+ if (this.schemas.size === 0) {
1091
+ await this.discoverSchemas();
1092
+ }
1093
+ return this.schemas.has(id);
1094
+ }
1095
+ /**
1096
+ * Get registry size
1097
+ */
1098
+ get size() {
1099
+ return this.schemas.size;
1100
+ }
1101
+ /**
1102
+ * Clear registry cache
1103
+ */
1104
+ clear() {
1105
+ this.schemas.clear();
1106
+ }
1107
+ };
1108
+ }
1109
+ });
4369
1110
  var init_cli = __esm({
4370
1111
  "src/schema/cli.ts"() {
4371
1112
  init_goneat_bridge();
@@ -4373,10 +1114,13 @@ var init_cli = __esm({
4373
1114
  init_registry2();
4374
1115
  init_utils();
4375
1116
  init_validator();
4376
- if (import.meta.url === `file://${process.argv[1]}`) {
4377
- const program = createCLI();
4378
- program.parse(process.argv);
4379
- }
1117
+ }
1118
+ });
1119
+ var init_export = __esm({
1120
+ "src/schema/export.ts"() {
1121
+ init_errors();
1122
+ init_registry2();
1123
+ init_validator();
4380
1124
  }
4381
1125
  });
4382
1126
 
@@ -4396,7 +1140,7 @@ var init_schema = __esm({
4396
1140
  });
4397
1141
 
4398
1142
  // src/telemetry/validators.ts
4399
- var init_validators2 = __esm({
1143
+ var init_validators = __esm({
4400
1144
  "src/telemetry/validators.ts"() {
4401
1145
  init_schema();
4402
1146
  }
@@ -4413,29 +1157,15 @@ var init_telemetry = __esm({
4413
1157
  init_histogram();
4414
1158
  init_taxonomy();
4415
1159
  init_types();
4416
- init_validators2();
1160
+ init_validators();
4417
1161
  metrics = new MetricsRegistry();
4418
1162
  }
4419
1163
  });
4420
-
4421
- // src/schema/validator.ts
4422
- var validator_exports = {};
4423
- __export(validator_exports, {
4424
- clearCache: () => clearCache,
4425
- compileSchema: () => compileSchema,
4426
- compileSchemaById: () => compileSchemaById,
4427
- getCacheSize: () => getCacheSize,
4428
- validateData: () => validateData,
4429
- validateDataBySchemaId: () => validateDataBySchemaId,
4430
- validateFile: () => validateFile,
4431
- validateFileBySchemaId: () => validateFileBySchemaId,
4432
- validateSchema: () => validateSchema
4433
- });
4434
1164
  async function loadMetaSchema(draft) {
4435
- const __filename3 = fileURLToPath(import.meta.url);
4436
- const __dirname4 = dirname(__filename3);
1165
+ const __filename2 = fileURLToPath(import.meta.url);
1166
+ const __dirname3 = dirname(__filename2);
4437
1167
  const metaSchemaPath = join(
4438
- __dirname4,
1168
+ __dirname3,
4439
1169
  "..",
4440
1170
  "..",
4441
1171
  "schemas",
@@ -4451,9 +1181,9 @@ async function loadVocabularySchemas(draft) {
4451
1181
  if (draft !== "draft-2019-09" && draft !== "draft-2020-12") {
4452
1182
  return [];
4453
1183
  }
4454
- const __filename3 = fileURLToPath(import.meta.url);
4455
- const __dirname4 = dirname(__filename3);
4456
- const vocabDir = join(__dirname4, "..", "..", "schemas", "crucible-ts", "meta", draft, "meta");
1184
+ const __filename2 = fileURLToPath(import.meta.url);
1185
+ const __dirname3 = dirname(__filename2);
1186
+ const vocabDir = join(__dirname3, "..", "..", "schemas", "crucible-ts", "meta", draft, "meta");
4457
1187
  const vocabFiles = draft === "draft-2020-12" ? [
4458
1188
  "core.json",
4459
1189
  "applicator.json",
@@ -4481,9 +1211,9 @@ async function loadVocabularySchemas(draft) {
4481
1211
  return schemas;
4482
1212
  }
4483
1213
  async function loadReferencedSchema(uri) {
4484
- const __filename3 = fileURLToPath(import.meta.url);
4485
- const __dirname4 = dirname(__filename3);
4486
- const repoRoot = join(__dirname4, "..", "..");
1214
+ const __filename2 = fileURLToPath(import.meta.url);
1215
+ const __dirname3 = dirname(__filename2);
1216
+ const repoRoot = join(__dirname3, "..", "..");
4487
1217
  let resolvedPath;
4488
1218
  if (uri.startsWith("https://schemas.fulmenhq.dev/")) {
4489
1219
  let relativePath = uri.replace("https://schemas.fulmenhq.dev/", "");
@@ -4658,104 +1388,6 @@ function validateData(data, validator) {
4658
1388
  }
4659
1389
  return result;
4660
1390
  }
4661
- async function validateFile(filePath, validator) {
4662
- try {
4663
- const content = await readFile(filePath, "utf-8");
4664
- let data;
4665
- try {
4666
- data = JSON.parse(content);
4667
- } catch {
4668
- data = parse(content);
4669
- }
4670
- return validateData(data, validator);
4671
- } catch (error) {
4672
- if (error instanceof SchemaValidationError) {
4673
- throw error;
4674
- }
4675
- throw SchemaValidationError.validationFailed(
4676
- filePath,
4677
- [
4678
- createDiagnostic(
4679
- "",
4680
- `Failed to read or parse file: ${error.message}`,
4681
- "file-read",
4682
- "ERROR",
4683
- "ajv"
4684
- )
4685
- ],
4686
- { type: "file", id: filePath }
4687
- );
4688
- }
4689
- }
4690
- async function validateSchema(schema) {
4691
- try {
4692
- let parsedSchema;
4693
- if (typeof schema === "string") {
4694
- try {
4695
- parsedSchema = JSON.parse(schema);
4696
- } catch {
4697
- parsedSchema = parse(schema);
4698
- }
4699
- } else if (Buffer.isBuffer(schema)) {
4700
- const content = schema.toString("utf-8");
4701
- try {
4702
- parsedSchema = JSON.parse(content);
4703
- } catch {
4704
- parsedSchema = parse(content);
4705
- }
4706
- } else {
4707
- parsedSchema = schema;
4708
- }
4709
- const dialect = detectDialect(parsedSchema);
4710
- const ajv = await getAjv(dialect);
4711
- const metaValid = ajv.validateSchema(parsedSchema);
4712
- if (!metaValid && ajv.errors) {
4713
- const diagnostics = ajv.errors.map(
4714
- (error) => createDiagnostic(
4715
- error.instancePath || "",
4716
- error.message || "Schema meta-validation failed",
4717
- error.keyword || "unknown",
4718
- "ERROR",
4719
- "ajv"
4720
- )
4721
- );
4722
- return { valid: false, diagnostics, source: "ajv" };
4723
- }
4724
- await compileSchema(parsedSchema);
4725
- return {
4726
- valid: true,
4727
- diagnostics: [],
4728
- source: "ajv"
4729
- };
4730
- } catch (error) {
4731
- if (error instanceof SchemaValidationError) {
4732
- return {
4733
- valid: false,
4734
- diagnostics: error.diagnostics,
4735
- source: "ajv"
4736
- };
4737
- }
4738
- return {
4739
- valid: false,
4740
- diagnostics: [
4741
- createDiagnostic(
4742
- "",
4743
- `Schema validation failed: ${error.message}`,
4744
- "schema-validation",
4745
- "ERROR",
4746
- "ajv"
4747
- )
4748
- ],
4749
- source: "ajv"
4750
- };
4751
- }
4752
- }
4753
- function clearCache() {
4754
- schemaCache.clear();
4755
- }
4756
- function getCacheSize() {
4757
- return schemaCache.size;
4758
- }
4759
1391
  async function compileSchemaById(schemaId, registryOptions) {
4760
1392
  try {
4761
1393
  const registry = getSchemaRegistry(registryOptions);
@@ -4783,15 +1415,6 @@ async function validateDataBySchemaId(data, schemaId, registryOptions) {
4783
1415
  throw error;
4784
1416
  }
4785
1417
  }
4786
- async function validateFileBySchemaId(filePath, schemaId, registryOptions) {
4787
- try {
4788
- const validator = await compileSchemaById(schemaId, registryOptions);
4789
- return validateFile(filePath, validator);
4790
- } catch (error) {
4791
- metrics.counter("schema_validation_errors").inc();
4792
- throw error;
4793
- }
4794
- }
4795
1418
  var ajvInstances, metaschemaReady, schemaCache;
4796
1419
  var init_validator = __esm({
4797
1420
  "src/schema/validator.ts"() {
@@ -4805,14 +1428,52 @@ var init_validator = __esm({
4805
1428
  schemaCache = /* @__PURE__ */ new Map();
4806
1429
  }
4807
1430
  });
1431
+
1432
+ // src/foundry/errors.ts
1433
+ var FoundryCatalogError;
1434
+ var init_errors2 = __esm({
1435
+ "src/foundry/errors.ts"() {
1436
+ FoundryCatalogError = class _FoundryCatalogError extends Error {
1437
+ constructor(message, catalog, cause) {
1438
+ super(message);
1439
+ this.catalog = catalog;
1440
+ this.cause = cause;
1441
+ this.name = "FoundryCatalogError";
1442
+ if (Error.captureStackTrace) {
1443
+ Error.captureStackTrace(this, _FoundryCatalogError);
1444
+ }
1445
+ }
1446
+ static invalidSchema(catalog, details, cause) {
1447
+ return new _FoundryCatalogError(
1448
+ `Invalid schema in ${catalog} catalog: ${details}`,
1449
+ catalog,
1450
+ cause
1451
+ );
1452
+ }
1453
+ static missingCatalog(catalog) {
1454
+ return new _FoundryCatalogError(`Catalog ${catalog} not found or could not be loaded`, catalog);
1455
+ }
1456
+ static invalidPattern(patternId, details) {
1457
+ return new _FoundryCatalogError(`Invalid pattern ${patternId}: ${details}`, "patterns");
1458
+ }
1459
+ static compilationError(patternId, details, cause) {
1460
+ return new _FoundryCatalogError(
1461
+ `Failed to compile pattern ${patternId}: ${details}`,
1462
+ "patterns",
1463
+ cause
1464
+ );
1465
+ }
1466
+ };
1467
+ }
1468
+ });
4808
1469
  function getConfigPath() {
4809
- if (__dirname3.includes("/dist/")) {
4810
- return join(__dirname3, "../../config/crucible-ts/library/foundry/signals.yaml");
1470
+ if (__dirname2.includes("/dist/")) {
1471
+ return join(__dirname2, "../../config/crucible-ts/library/foundry/signals.yaml");
4811
1472
  }
4812
- return join(__dirname3, "../../../config/crucible-ts/library/foundry/signals.yaml");
1473
+ return join(__dirname2, "../../../config/crucible-ts/library/foundry/signals.yaml");
4813
1474
  }
4814
- async function loadCatalog2() {
4815
- const filePath = SSOT_PATHS2.signals;
1475
+ async function loadCatalog() {
1476
+ const filePath = SSOT_PATHS.signals;
4816
1477
  const catalogName = "signals";
4817
1478
  try {
4818
1479
  let content;
@@ -4876,7 +1537,7 @@ async function loadCatalog2() {
4876
1537
  }
4877
1538
  async function getCatalog() {
4878
1539
  if (!cachedCatalog) {
4879
- cachedCatalog = await loadCatalog2();
1540
+ cachedCatalog = await loadCatalog();
4880
1541
  }
4881
1542
  return cachedCatalog;
4882
1543
  }
@@ -4905,14 +1566,14 @@ async function getBehavior(id) {
4905
1566
  async function getSignalCatalog() {
4906
1567
  return await getCatalog();
4907
1568
  }
4908
- var __filename2, __dirname3, SSOT_PATHS2, SCHEMA_ID, cachedCatalog;
1569
+ var __filename, __dirname2, SSOT_PATHS, SCHEMA_ID, cachedCatalog;
4909
1570
  var init_catalog = __esm({
4910
1571
  "src/foundry/signals/catalog.ts"() {
4911
1572
  init_validator();
4912
1573
  init_errors2();
4913
- __filename2 = fileURLToPath(import.meta.url);
4914
- __dirname3 = dirname(__filename2);
4915
- SSOT_PATHS2 = {
1574
+ __filename = fileURLToPath(import.meta.url);
1575
+ __dirname2 = dirname(__filename);
1576
+ SSOT_PATHS = {
4916
1577
  signals: getConfigPath()
4917
1578
  };
4918
1579
  SCHEMA_ID = "library/foundry/v1.0.0/signals";
@@ -4921,7 +1582,7 @@ var init_catalog = __esm({
4921
1582
  });
4922
1583
 
4923
1584
  // src/foundry/signals/capabilities.ts
4924
- function getPlatform2() {
1585
+ function getPlatform() {
4925
1586
  const platform = process.platform;
4926
1587
  switch (platform) {
4927
1588
  case "linux":
@@ -4936,33 +1597,33 @@ function getPlatform2() {
4936
1597
  return "unknown";
4937
1598
  }
4938
1599
  }
4939
- function isPOSIX2() {
4940
- const platform = getPlatform2();
1600
+ function isPOSIX() {
1601
+ const platform = getPlatform();
4941
1602
  return platform === "linux" || platform === "darwin" || platform === "freebsd";
4942
1603
  }
4943
- function isWindows2() {
4944
- return getPlatform2() === "win32";
1604
+ function isWindows() {
1605
+ return getPlatform() === "win32";
4945
1606
  }
4946
1607
  async function supportsSignal(signalName) {
4947
1608
  const signal = await getSignal(signalName);
4948
1609
  if (!signal) {
4949
1610
  return false;
4950
1611
  }
4951
- if (isPOSIX2()) {
1612
+ if (isPOSIX()) {
4952
1613
  return true;
4953
1614
  }
4954
- if (isWindows2()) {
1615
+ if (isWindows()) {
4955
1616
  return signal.windows_event !== null;
4956
1617
  }
4957
1618
  return false;
4958
1619
  }
4959
- function supportsSignalExitCodes2() {
4960
- return isPOSIX2();
1620
+ function supportsSignalExitCodes() {
1621
+ return isPOSIX();
4961
1622
  }
4962
- async function getPlatformCapabilities2() {
4963
- const platform = getPlatform2();
4964
- const isPosix = isPOSIX2();
4965
- const isWin = isWindows2();
1623
+ async function getPlatformCapabilities() {
1624
+ const platform = getPlatform();
1625
+ const isPosix = isPOSIX();
1626
+ const isWin = isWindows();
4966
1627
  const catalog = await getSignalCatalog();
4967
1628
  const supported = [];
4968
1629
  const unsupported = [];
@@ -4986,7 +1647,7 @@ async function getPlatformCapabilities2() {
4986
1647
  isPOSIX: isPosix,
4987
1648
  isWindows: isWin,
4988
1649
  supportsNativeSignals: isPosix,
4989
- supportsSignalExitCodes: supportsSignalExitCodes2(),
1650
+ supportsSignalExitCodes: supportsSignalExitCodes(),
4990
1651
  supportedSignals: supported,
4991
1652
  unsupportedSignals: unsupported,
4992
1653
  mappedSignals: mapped
@@ -4997,7 +1658,7 @@ async function getSignalNumber(signalName) {
4997
1658
  if (!signal) {
4998
1659
  return null;
4999
1660
  }
5000
- const platform = getPlatform2();
1661
+ const platform = getPlatform();
5001
1662
  if (signal.platform_overrides) {
5002
1663
  if (platform === "darwin" && signal.platform_overrides.darwin !== void 0) {
5003
1664
  return signal.platform_overrides.darwin;
@@ -5015,7 +1676,7 @@ async function getWindowsEvent(signalName) {
5015
1676
  }
5016
1677
  return signal.windows_event;
5017
1678
  }
5018
- var init_capabilities2 = __esm({
1679
+ var init_capabilities = __esm({
5019
1680
  "src/foundry/signals/capabilities.ts"() {
5020
1681
  init_catalog();
5021
1682
  }
@@ -5025,7 +1686,7 @@ var init_capabilities2 = __esm({
5025
1686
  function createConfigReloadEndpoint(options) {
5026
1687
  const { loader, validator, onReload: onReload2, auth, rateLimit, logger, telemetry } = options;
5027
1688
  return async (payload, req) => {
5028
- const correlationId = payload.correlation_id ?? generateCorrelationId2();
1689
+ const correlationId = payload.correlation_id ?? generateCorrelationId();
5029
1690
  const authResult = await auth(req);
5030
1691
  if (!authResult.authenticated) {
5031
1692
  if (logger) {
@@ -5142,7 +1803,7 @@ function createConfigReloadEndpoint(options) {
5142
1803
  }
5143
1804
  };
5144
1805
  }
5145
- function generateCorrelationId2() {
1806
+ function generateCorrelationId() {
5146
1807
  return `cfg-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
5147
1808
  }
5148
1809
  var init_config_reload_endpoint = __esm({
@@ -5442,7 +2103,7 @@ async function ensureSupported(signalName, options = {}) {
5442
2103
  return;
5443
2104
  }
5444
2105
  let message = `Signal ${signal.name} is not supported on this platform`;
5445
- if (isWindows2() && includeGuidance) {
2106
+ if (isWindows() && includeGuidance) {
5446
2107
  const fallback = await getFallbackMetadata(signalName);
5447
2108
  if (fallback) {
5448
2109
  message += `. ${fallback.log_message}`;
@@ -5462,7 +2123,7 @@ async function ensureSupported(signalName, options = {}) {
5462
2123
  throw FoundryCatalogError.invalidSchema("signals", message);
5463
2124
  }
5464
2125
  function ensureSignalExitCodesSupported() {
5465
- if (!isPOSIX2()) {
2126
+ if (!isPOSIX()) {
5466
2127
  throw FoundryCatalogError.invalidSchema(
5467
2128
  "signals",
5468
2129
  "Signal-based exit codes (128+N pattern) are not supported on this platform. Windows does not propagate signal numbers via exit codes. Use explicit exit codes or monitor via HTTP admin endpoint."
@@ -5470,7 +2131,7 @@ function ensureSignalExitCodesSupported() {
5470
2131
  }
5471
2132
  }
5472
2133
  function ensurePOSIX() {
5473
- if (!isPOSIX2()) {
2134
+ if (!isPOSIX()) {
5474
2135
  throw FoundryCatalogError.invalidSchema(
5475
2136
  "signals",
5476
2137
  "This operation requires a POSIX-compliant platform (Linux, macOS, FreeBSD). Current platform does not support native signal handling."
@@ -5478,7 +2139,7 @@ function ensurePOSIX() {
5478
2139
  }
5479
2140
  }
5480
2141
  function ensureWindows() {
5481
- if (!isWindows2()) {
2142
+ if (!isWindows()) {
5482
2143
  throw FoundryCatalogError.invalidSchema(
5483
2144
  "signals",
5484
2145
  "This operation requires Windows platform. Current platform uses native signals."
@@ -5488,7 +2149,7 @@ function ensureWindows() {
5488
2149
  var init_guards = __esm({
5489
2150
  "src/foundry/signals/guards.ts"() {
5490
2151
  init_errors2();
5491
- init_capabilities2();
2152
+ init_capabilities();
5492
2153
  init_catalog();
5493
2154
  init_windows();
5494
2155
  }
@@ -5498,7 +2159,7 @@ var init_guards = __esm({
5498
2159
  function createSignalEndpoint(options) {
5499
2160
  const { manager, auth, rateLimit, logger, telemetry, allowedSignals } = options;
5500
2161
  return async (payload, req) => {
5501
- const correlationId = payload.correlation_id ?? generateCorrelationId3();
2162
+ const correlationId = payload.correlation_id ?? generateCorrelationId2();
5502
2163
  const authResult = await auth(req);
5503
2164
  if (!authResult.authenticated) {
5504
2165
  if (logger) {
@@ -5621,7 +2282,7 @@ function normalizeSignalName(signal) {
5621
2282
  }
5622
2283
  return `SIG${upper}`;
5623
2284
  }
5624
- function generateCorrelationId3() {
2285
+ function generateCorrelationId2() {
5625
2286
  return `sig-${Date.now()}-${Math.random().toString(36).substring(2, 9)}`;
5626
2287
  }
5627
2288
  function createBearerTokenAuth(expectedToken) {
@@ -5675,7 +2336,7 @@ function createSimpleRateLimiter(requestsPerMinute) {
5675
2336
  }
5676
2337
  var init_http_helper = __esm({
5677
2338
  "src/foundry/signals/http-helper.ts"() {
5678
- init_capabilities2();
2339
+ init_capabilities();
5679
2340
  }
5680
2341
  });
5681
2342
 
@@ -5686,7 +2347,7 @@ function createSignalManager(options = {}) {
5686
2347
  var SignalManager;
5687
2348
  var init_manager = __esm({
5688
2349
  "src/foundry/signals/manager.ts"() {
5689
- init_capabilities2();
2350
+ init_capabilities();
5690
2351
  init_catalog();
5691
2352
  init_double_tap();
5692
2353
  init_windows();
@@ -5719,7 +2380,7 @@ var init_manager = __esm({
5719
2380
  const signalName = typeof signal === "string" ? signal : signal;
5720
2381
  const supported = await supportsSignal(signalName);
5721
2382
  if (!supported) {
5722
- if (isWindows2()) {
2383
+ if (isWindows()) {
5723
2384
  await handleWindowsFallback(signalName, {
5724
2385
  logger: this.options.logger,
5725
2386
  telemetry: this.options.telemetry
@@ -6086,7 +2747,7 @@ var init_reload = __esm({
6086
2747
  // src/foundry/signals/index.ts
6087
2748
  var init_signals = __esm({
6088
2749
  "src/foundry/signals/index.ts"() {
6089
- init_capabilities2();
2750
+ init_capabilities();
6090
2751
  init_catalog();
6091
2752
  init_config_reload_endpoint();
6092
2753
  init_control_discovery_endpoint();
@@ -6103,6 +2764,6 @@ var init_signals = __esm({
6103
2764
  // src/signals/index.ts
6104
2765
  init_signals();
6105
2766
 
6106
- export { ConfigReloadTracker, SignalManager, createBearerTokenAuth, createConfigReloadEndpoint, createConfigReloadHandler, createControlDiscoveryEndpoint, createDoubleTapTracker, createSignalEndpoint, createSignalManager, createSimpleRateLimiter, ensurePOSIX, ensureSignalExitCodesSupported, ensureSupported, ensureWindows, getBehavior, getFallbackMetadata, getHttpFallbackGuidance, getPlatform2 as getPlatform, getPlatformCapabilities2 as getPlatformCapabilities, getSignal, getSignalCatalog, getSignalNumber, getSignalsVersion, getWindowTimeRemaining, getWindowsEvent, handleDoubleTap, handleWindowsFallback, isPOSIX2 as isPOSIX, isWindows2 as isWindows, isWithinWindow, listBehaviors, listSignals, onAnyShutdown, onEmergencyQuit, onReload, onShutdown, onUSR1, onUSR2, requiresFallback, resetDoubleTap, supportsSignal, supportsSignalExitCodes2 as supportsSignalExitCodes };
2767
+ export { ConfigReloadTracker, SignalManager, createBearerTokenAuth, createConfigReloadEndpoint, createConfigReloadHandler, createControlDiscoveryEndpoint, createDoubleTapTracker, createSignalEndpoint, createSignalManager, createSimpleRateLimiter, ensurePOSIX, ensureSignalExitCodesSupported, ensureSupported, ensureWindows, getBehavior, getFallbackMetadata, getHttpFallbackGuidance, getPlatform, getPlatformCapabilities, getSignal, getSignalCatalog, getSignalNumber, getSignalsVersion, getWindowTimeRemaining, getWindowsEvent, handleDoubleTap, handleWindowsFallback, isPOSIX, isWindows, isWithinWindow, listBehaviors, listSignals, onAnyShutdown, onEmergencyQuit, onReload, onShutdown, onUSR1, onUSR2, requiresFallback, resetDoubleTap, supportsSignal, supportsSignalExitCodes };
6107
2768
  //# sourceMappingURL=index.js.map
6108
2769
  //# sourceMappingURL=index.js.map