@fulmenhq/tsfulmen 0.1.13 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +73 -512
- package/README.md +111 -28
- package/config/crucible-ts/agentic/roles/README.md +76 -0
- package/config/crucible-ts/agentic/roles/cicd.yaml +82 -0
- package/config/crucible-ts/agentic/roles/dataeng.yaml +104 -0
- package/config/crucible-ts/agentic/roles/devlead.yaml +84 -0
- package/config/crucible-ts/agentic/roles/devrev.yaml +105 -0
- package/config/crucible-ts/agentic/roles/entarch.yaml +101 -0
- package/config/crucible-ts/agentic/roles/infoarch.yaml +95 -0
- package/config/crucible-ts/agentic/roles/prodmktg.yaml +92 -0
- package/config/crucible-ts/agentic/roles/qa.yaml +148 -0
- package/config/crucible-ts/agentic/roles/secrev.yaml +101 -0
- package/config/crucible-ts/agentic/roles/uxdev.yaml +168 -0
- package/config/crucible-ts/branding/ecosystem.yaml +26 -0
- package/config/crucible-ts/library/foundry/exit-codes.snapshot.json +26 -0
- package/config/crucible-ts/library/foundry/exit-codes.yaml +28 -3
- package/config/crucible-ts/library/foundry/patterns.yaml +2 -2
- package/config/crucible-ts/library/foundry/signal-resolution-fixtures.yaml +207 -0
- package/config/crucible-ts/library/foundry/signals.yaml +21 -0
- package/config/crucible-ts/library/foundry/simplified-modes.snapshot.json +9 -1
- package/config/crucible-ts/library/{foundry/similarity-fixtures.yaml → similarity/fixtures.yaml} +1 -1
- package/config/crucible-ts/library/v1.0.0/module-manifest.yaml +1 -2
- package/config/crucible-ts/taxonomy/fixture-catalog.yaml +145 -0
- package/config/crucible-ts/taxonomy/languages.yaml +2 -2
- package/config/crucible-ts/taxonomy/library/foundry-catalogs/v1.1.0/catalogs.yaml +77 -0
- package/config/crucible-ts/taxonomy/library/platform-modules/v1.1.0/modules.yaml +722 -0
- package/config/crucible-ts/taxonomy/metrics.yaml +1 -1
- package/config/crucible-ts/taxonomy/repository-categories.yaml +134 -1
- package/dist/appidentity/index.d.ts +117 -35
- package/dist/appidentity/index.js +752 -592
- package/dist/appidentity/index.js.map +1 -1
- package/dist/config/index.js +118 -6
- package/dist/config/index.js.map +1 -1
- package/dist/crucible/index.js +118 -6
- package/dist/crucible/index.js.map +1 -1
- package/dist/errors/index.js +118 -6
- package/dist/errors/index.js.map +1 -1
- package/dist/foundry/index.d.ts +13 -676
- package/dist/foundry/index.js +118 -6
- package/dist/foundry/index.js.map +1 -1
- package/dist/foundry/similarity/index.d.ts +2 -2
- package/dist/fulhash/index.d.ts +64 -12
- package/dist/fulhash/index.js +292 -53
- package/dist/fulhash/index.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +753 -593
- package/dist/index.js.map +1 -1
- package/dist/{manager-D27vrdaS.d.ts → manager-CH3fX7zO.d.ts} +1 -1
- package/dist/pathfinder/index.js +368 -59
- package/dist/pathfinder/index.js.map +1 -1
- package/dist/reports/license-inventory.csv +302 -0
- package/dist/schema/index.js +118 -6
- package/dist/schema/index.js.map +1 -1
- package/dist/signals/index.d.ts +675 -0
- package/dist/signals/index.js +5790 -0
- package/dist/signals/index.js.map +1 -0
- package/dist/similarity/index.d.ts +2 -0
- package/dist/similarity/index.js +136 -0
- package/dist/similarity/index.js.map +1 -0
- package/dist/{suggest-Cv7SVQRu.d.ts → suggest-D8LbwtPV.d.ts} +1 -1
- package/dist/telemetry/http/index.js +704 -591
- package/dist/telemetry/http/index.js.map +1 -1
- package/dist/telemetry/index.js +118 -6
- package/dist/telemetry/index.js.map +1 -1
- package/dist/telemetry/prometheus/index.d.ts +1 -1
- package/dist/telemetry/prometheus/index.js +175 -11
- package/dist/telemetry/prometheus/index.js.map +1 -1
- package/package.json +15 -6
- package/schemas/crucible-ts/assessment/v1.0.0/severity-definitions.schema.json +1 -1
- package/schemas/crucible-ts/config/fulmen-ecosystem/v1.0.0/fulmen-config-paths.schema.json +1 -1
- package/schemas/crucible-ts/config/repository/app-identity/v1.0.0/app-identity.schema.json +3 -3
- package/schemas/crucible-ts/config/repository/v1.0.0/lifecycle-phase.json +1 -1
- package/schemas/crucible-ts/config/repository-category/codex/v1.0.0/codex-config.schema.json +1 -1
- package/schemas/crucible-ts/config/standards/v1.0.0/adr-adoption-status.json +1 -1
- package/schemas/crucible-ts/config/standards/v1.0.0/adr-frontmatter.schema.json +3 -3
- package/schemas/crucible-ts/config/standards/v1.0.0/adr-lifecycle-status.json +1 -1
- package/schemas/crucible-ts/config/sync-keys.schema.yaml +14 -0
- package/schemas/crucible-ts/content/ssot-provenance/v1.0.0/ssot-provenance.schema.json +1 -1
- package/schemas/crucible-ts/design/README.md +159 -0
- package/schemas/crucible-ts/design/core/v1.0.0/component-states.schema.json +204 -0
- package/schemas/crucible-ts/design/core/v1.0.0/semantic-colors.schema.json +179 -0
- package/schemas/crucible-ts/design/core/v1.0.0/spacing-scale.schema.json +165 -0
- package/schemas/crucible-ts/design/core/v1.0.0/typography-roles.schema.json +195 -0
- package/schemas/crucible-ts/design/tui/v1.0.0/color-palette.schema.json +303 -0
- package/schemas/crucible-ts/design/tui/v1.0.0/component.schema.json +374 -0
- package/schemas/crucible-ts/design/tui/v1.0.0/layout.schema.json +272 -0
- package/schemas/crucible-ts/design/tui/v1.0.0/theme.schema.json +205 -0
- package/schemas/crucible-ts/design/tui/v1.0.0/typography.schema.json +316 -0
- package/schemas/crucible-ts/devsecops/lorage-central/activity/v1.0.0/activity.schema.json +1 -1
- package/schemas/crucible-ts/devsecops/lorage-central/credentials/v1.0.0/credentials.schema.json +1 -1
- package/schemas/crucible-ts/devsecops/lorage-central/policy/v1.0.0/policy.schema.json +1 -1
- package/schemas/crucible-ts/devsecops/lorage-central/recipe/v1.0.0/recipe.schema.json +1 -1
- package/schemas/crucible-ts/devsecops/lorage-central/runbooks/v1.0.0/runbook.schema.json +1 -1
- package/schemas/crucible-ts/devsecops/lorage-central/tenant/v1.0.0/tenant.schema.json +1 -1
- package/schemas/crucible-ts/devsecops/secrets/v1.0.0/secrets.schema.json +1 -1
- package/schemas/crucible-ts/error-handling/v1.0.0/error-response.schema.json +1 -1
- package/schemas/crucible-ts/library/foundry/v1.0.0/country-codes.schema.json +1 -1
- package/schemas/crucible-ts/library/foundry/v1.0.0/exit-codes.schema.json +1 -1
- package/schemas/crucible-ts/library/foundry/v1.0.0/http-status-groups.schema.json +1 -1
- package/schemas/crucible-ts/library/foundry/v1.0.0/mime-types.schema.json +1 -1
- package/schemas/crucible-ts/library/foundry/v1.0.0/patterns.schema.json +1 -1
- package/schemas/crucible-ts/library/foundry/v1.0.0/signal-resolution-fixtures.schema.json +140 -0
- package/schemas/crucible-ts/library/foundry/v1.0.0/signals.schema.json +6 -1
- package/schemas/crucible-ts/library/fulencode/v1.0.0/fulencode-config.schema.json +1 -1
- package/schemas/crucible-ts/library/fulhash/v1.0.0/checksum-string.schema.json +2 -2
- package/schemas/crucible-ts/library/fulhash/v1.0.0/digest.schema.json +61 -1
- package/schemas/crucible-ts/library/fulhash/v1.0.0/fixtures.schema.json +1 -1
- package/schemas/crucible-ts/library/fulpack/v1.0.0/archive-entry.schema.json +1 -1
- package/schemas/crucible-ts/library/fulpack/v1.0.0/archive-info.schema.json +1 -1
- package/schemas/crucible-ts/library/fulpack/v1.0.0/archive-manifest.schema.json +2 -2
- package/schemas/crucible-ts/library/fulpack/v1.0.0/create-options.schema.json +1 -1
- package/schemas/crucible-ts/library/fulpack/v1.0.0/extract-options.schema.json +1 -1
- package/schemas/crucible-ts/library/fulpack/v1.0.0/extract-result.schema.json +1 -1
- package/schemas/crucible-ts/library/fulpack/v1.0.0/scan-options.schema.json +1 -1
- package/schemas/crucible-ts/library/fulpack/v1.0.0/validation-result.schema.json +1 -1
- package/schemas/crucible-ts/library/module-manifest/v1.0.0/module-manifest.schema.json +1 -1
- package/schemas/crucible-ts/library/{foundry → similarity}/v1.0.0/similarity.schema.json +2 -2
- package/schemas/crucible-ts/library/{foundry → similarity}/v2.0.0/similarity.schema.json +2 -2
- package/schemas/crucible-ts/observability/metrics/v1.0.0/metrics-event.schema.json +1 -1
- package/schemas/crucible-ts/pathfinder/v1.0.0/find-query.schema.json +1 -1
- package/schemas/crucible-ts/pathfinder/v1.0.0/finder-config.schema.json +1 -1
- package/schemas/crucible-ts/pathfinder/v1.0.0/path-result.schema.json +1 -1
- package/schemas/crucible-ts/protocol/http/v1.0.0/error-response.schema.json +1 -1
- package/schemas/crucible-ts/protocol/http/v1.0.0/health-response.schema.json +1 -1
- package/schemas/crucible-ts/protocol/http/v1.0.0/success-response.schema.json +1 -1
- package/schemas/crucible-ts/protocol/http/v1.0.0/version-response.schema.json +1 -1
- package/schemas/crucible-ts/server/management/v1.0.0/server-management.schema.json +1 -1
- package/schemas/crucible-ts/standards/publishing/v1.0.0/spec-catalog.schema.json +134 -0
- package/schemas/crucible-ts/taxonomy/devsecops/auth-methods/v1.0.0/auth-methods-key.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/auth-methods/v1.0.0/auth-methods-metadata.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/geo/v1.0.0/geo-key.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/geo/v1.0.0/geo-metadata.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/infra-phases/v1.0.0/infra-phases-key.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/infra-phases/v1.0.0/infra-phases-metadata.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/infra-providers/v1.0.0/infra-providers-key.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/infra-providers/v1.0.0/infra-providers-metadata.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/devsecops/modules/v1.0.0/devsecops-module-entry.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/fixture/v1.0.0/fixture-catalog.schema.json +166 -0
- package/schemas/crucible-ts/taxonomy/language/v1.0.0/language-key.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/language/v1.0.0/language-metadata.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/library/foundry-catalogs/v1.1.0/catalog-entry.schema.json +98 -0
- package/schemas/crucible-ts/taxonomy/library/fulencode/detection-confidence/v1.0.0/levels.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/library/fulencode/encoding-families/v1.0.0/families.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/library/fulencode/normalization-profiles/v1.0.0/profiles.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/library/fulhash/algorithms/v1.0.0/algorithms.yaml +16 -0
- package/schemas/crucible-ts/taxonomy/library/modules/v1.0.0/module-entry.schema.json +1 -1
- package/schemas/crucible-ts/taxonomy/library/modules/v1.1.0/module-entry.schema.json +436 -0
- package/schemas/crucible-ts/taxonomy/repository-category/v1.0.0/category-key.schema.json +16 -8
- package/schemas/crucible-ts/taxonomy/repository-category/v1.0.0/category-metadata.schema.json +1 -1
- package/schemas/crucible-ts/upstream/3leaps/PROVENANCE.md +43 -0
- package/schemas/crucible-ts/upstream/3leaps/agentic/v0/role-prompt.schema.json +183 -0
- package/schemas/crucible-ts/upstream/3leaps/ailink/v0/prompt.schema.json +204 -0
- package/schemas/crucible-ts/upstream/3leaps/ailink/v0/search-response.schema.json +152 -0
- package/schemas/crucible-ts/upstream/README.md +50 -0
- package/schemas/crucible-ts/web/branding/v1.0.0/site-branding.schema.json +1 -1
- package/schemas/crucible-ts/web/styling/v1.0.0/site-styling.schema.json +1 -1
- package/schemas/crucible-ts/config/goneat/README.md +0 -60
- package/schemas/crucible-ts/config/goneat/v1.0.0/dates.yaml +0 -234
- package/schemas/crucible-ts/config/goneat/v1.0.0/goneat-config.yaml +0 -344
- package/schemas/crucible-ts/config/goneat/v1.0.0/lifecycle-phase.json +0 -20
- package/schemas/crucible-ts/config/goneat/v1.0.0/release-phase.json +0 -17
- package/schemas/crucible-ts/config/goneat/v1.0.0/security-policy.yaml +0 -178
- package/schemas/crucible-ts/config/goneat/v1.0.0/version-policy.schema.yaml +0 -205
- package/schemas/crucible-ts/tooling/goneat-tools/v1.0.0/README.md +0 -177
- package/schemas/crucible-ts/tooling/goneat-tools/v1.0.0/goneat-tools-config.schema.yaml +0 -146
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import 'crypto';
|
|
2
1
|
import { spawn } from 'child_process';
|
|
3
2
|
import { readFile, writeFile, access, mkdir } from 'fs/promises';
|
|
4
3
|
import { parse, stringify } from 'yaml';
|
|
@@ -10,6 +9,7 @@ import addFormats from 'ajv-formats';
|
|
|
10
9
|
import { Readable } from 'stream';
|
|
11
10
|
import picomatch from 'picomatch';
|
|
12
11
|
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';
|
|
12
|
+
import 'crypto';
|
|
13
13
|
import { Command } from 'commander';
|
|
14
14
|
|
|
15
15
|
var __defProp = Object.defineProperty;
|
|
@@ -33,68 +33,6 @@ var init_constants = __esm({
|
|
|
33
33
|
MAX_ANCESTOR_SEARCH_DEPTH = 20;
|
|
34
34
|
}
|
|
35
35
|
});
|
|
36
|
-
var init_correlation = __esm({
|
|
37
|
-
"src/errors/correlation.ts"() {
|
|
38
|
-
}
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
// src/errors/severity.ts
|
|
42
|
-
function getDefaultSeverity() {
|
|
43
|
-
return {
|
|
44
|
-
name: Severity.MEDIUM,
|
|
45
|
-
level: 2
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
var Severity, SEVERITY_LEVELS;
|
|
49
|
-
var init_severity = __esm({
|
|
50
|
-
"src/errors/severity.ts"() {
|
|
51
|
-
Severity = {
|
|
52
|
-
INFO: "info",
|
|
53
|
-
LOW: "low",
|
|
54
|
-
MEDIUM: "medium",
|
|
55
|
-
HIGH: "high",
|
|
56
|
-
CRITICAL: "critical"
|
|
57
|
-
};
|
|
58
|
-
SEVERITY_LEVELS = {
|
|
59
|
-
info: 0,
|
|
60
|
-
low: 1,
|
|
61
|
-
medium: 2,
|
|
62
|
-
high: 3,
|
|
63
|
-
critical: 4
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
// src/errors/serialization.ts
|
|
69
|
-
function extractErrorMessage(error) {
|
|
70
|
-
if (error instanceof Error) {
|
|
71
|
-
return error.message;
|
|
72
|
-
}
|
|
73
|
-
if (isErrorLike(error)) {
|
|
74
|
-
return error.message;
|
|
75
|
-
}
|
|
76
|
-
if (typeof error === "string") {
|
|
77
|
-
return error;
|
|
78
|
-
}
|
|
79
|
-
return String(error);
|
|
80
|
-
}
|
|
81
|
-
function extractStackTrace(error) {
|
|
82
|
-
if (error instanceof Error) {
|
|
83
|
-
return error.stack;
|
|
84
|
-
}
|
|
85
|
-
if (isErrorLike(error) && typeof error.stack === "string") {
|
|
86
|
-
return error.stack;
|
|
87
|
-
}
|
|
88
|
-
return void 0;
|
|
89
|
-
}
|
|
90
|
-
function isErrorLike(value) {
|
|
91
|
-
return typeof value === "object" && value !== null && "message" in value && typeof value.message === "string";
|
|
92
|
-
}
|
|
93
|
-
var init_serialization = __esm({
|
|
94
|
-
"src/errors/serialization.ts"() {
|
|
95
|
-
init_severity();
|
|
96
|
-
}
|
|
97
|
-
});
|
|
98
36
|
|
|
99
37
|
// src/schema/errors.ts
|
|
100
38
|
var errors_exports = {};
|
|
@@ -1585,7 +1523,10 @@ async function loadReferencedSchema(uri) {
|
|
|
1585
1523
|
const repoRoot = join(__dirname4, "..", "..");
|
|
1586
1524
|
let resolvedPath;
|
|
1587
1525
|
if (uri.startsWith("https://schemas.fulmenhq.dev/")) {
|
|
1588
|
-
|
|
1526
|
+
let relativePath = uri.replace("https://schemas.fulmenhq.dev/", "");
|
|
1527
|
+
if (relativePath.startsWith("crucible/")) {
|
|
1528
|
+
relativePath = relativePath.slice("crucible/".length);
|
|
1529
|
+
}
|
|
1589
1530
|
if (relativePath.startsWith("config/taxonomy/")) {
|
|
1590
1531
|
resolvedPath = join(
|
|
1591
1532
|
repoRoot,
|
|
@@ -1802,7 +1743,9 @@ async function compileSchemaById(schemaId, registryOptions) {
|
|
|
1802
1743
|
const aliases = [];
|
|
1803
1744
|
const normalizedRelativePath = metadata.relativePath.replace(/\\/g, "/");
|
|
1804
1745
|
if (normalizedRelativePath) {
|
|
1805
|
-
aliases.push(
|
|
1746
|
+
aliases.push(
|
|
1747
|
+
new URL(`crucible/${normalizedRelativePath}`, "https://schemas.fulmenhq.dev/").toString()
|
|
1748
|
+
);
|
|
1806
1749
|
}
|
|
1807
1750
|
return compileSchema(content, { aliases });
|
|
1808
1751
|
} catch (error) {
|
|
@@ -2320,6 +2263,12 @@ var init_exitCodes = __esm({
|
|
|
2320
2263
|
EXIT_TEST_USAGE_ERROR: 94,
|
|
2321
2264
|
EXIT_TEST_NO_TESTS_COLLECTED: 95,
|
|
2322
2265
|
EXIT_COVERAGE_THRESHOLD_NOT_MET: 96,
|
|
2266
|
+
// Shell & Process Control (124-127)
|
|
2267
|
+
// Exit codes from shell conventions and process control utilities (timeout, exec)
|
|
2268
|
+
EXIT_TIMEOUT: 124,
|
|
2269
|
+
EXIT_TIMEOUT_INTERNAL: 125,
|
|
2270
|
+
EXIT_CANNOT_EXECUTE: 126,
|
|
2271
|
+
EXIT_NOT_FOUND: 127,
|
|
2323
2272
|
// Signal-Induced Exits (128-165)
|
|
2324
2273
|
// 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.
|
|
2325
2274
|
EXIT_SIGNAL_HUP: 129,
|
|
@@ -2657,6 +2606,36 @@ var init_exitCodes = __esm({
|
|
|
2657
2606
|
context: "Code coverage validation, quality gate failure",
|
|
2658
2607
|
category: "testing"
|
|
2659
2608
|
},
|
|
2609
|
+
124: {
|
|
2610
|
+
code: 124,
|
|
2611
|
+
name: "EXIT_TIMEOUT",
|
|
2612
|
+
description: "Command timed out before completion",
|
|
2613
|
+
context: "GNU timeout or similar utility terminated command after deadline",
|
|
2614
|
+
category: "shell"
|
|
2615
|
+
},
|
|
2616
|
+
125: {
|
|
2617
|
+
code: 125,
|
|
2618
|
+
name: "EXIT_TIMEOUT_INTERNAL",
|
|
2619
|
+
description: "Timeout utility itself failed",
|
|
2620
|
+
context: "Error in timeout tool before or during command execution (not command failure)",
|
|
2621
|
+
category: "shell"
|
|
2622
|
+
},
|
|
2623
|
+
126: {
|
|
2624
|
+
code: 126,
|
|
2625
|
+
name: "EXIT_CANNOT_EXECUTE",
|
|
2626
|
+
description: "Command found but could not be executed",
|
|
2627
|
+
context: "Permission denied, not executable, exec format error",
|
|
2628
|
+
category: "shell",
|
|
2629
|
+
bsdEquivalent: "EX_NOPERM (partial)"
|
|
2630
|
+
},
|
|
2631
|
+
127: {
|
|
2632
|
+
code: 127,
|
|
2633
|
+
name: "EXIT_NOT_FOUND",
|
|
2634
|
+
description: "Command not found",
|
|
2635
|
+
context: "Executable not found in PATH or specified path does not exist",
|
|
2636
|
+
category: "shell",
|
|
2637
|
+
bsdEquivalent: "EX_UNAVAILABLE (partial)"
|
|
2638
|
+
},
|
|
2660
2639
|
129: {
|
|
2661
2640
|
code: 129,
|
|
2662
2641
|
name: "EXIT_SIGNAL_HUP",
|
|
@@ -4865,554 +4844,179 @@ var init_cache = __esm({
|
|
|
4865
4844
|
cachedIdentity = null;
|
|
4866
4845
|
}
|
|
4867
4846
|
});
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
const exists = await fileExists(options.path);
|
|
4871
|
-
if (!exists) {
|
|
4872
|
-
throw AppIdentityError.notFound([options.path]);
|
|
4873
|
-
}
|
|
4874
|
-
return { path: options.path, source: "explicit" };
|
|
4875
|
-
}
|
|
4876
|
-
const envPath = process.env[APP_IDENTITY_ENV_VAR];
|
|
4877
|
-
if (envPath) {
|
|
4878
|
-
const exists = await fileExists(envPath);
|
|
4879
|
-
if (!exists) {
|
|
4880
|
-
throw AppIdentityError.envOverrideMissing(envPath);
|
|
4881
|
-
}
|
|
4882
|
-
return { path: envPath, source: "env" };
|
|
4883
|
-
}
|
|
4884
|
-
const startDir = options?.startDir || process.cwd();
|
|
4885
|
-
const result = await searchAncestors(startDir);
|
|
4886
|
-
if (result) {
|
|
4887
|
-
return { path: result, source: "ancestor" };
|
|
4888
|
-
}
|
|
4889
|
-
return null;
|
|
4890
|
-
}
|
|
4891
|
-
async function searchAncestors(startDir) {
|
|
4892
|
-
let currentDir = startDir;
|
|
4893
|
-
const searchedPaths = [];
|
|
4894
|
-
for (let i = 0; i < MAX_ANCESTOR_SEARCH_DEPTH; i++) {
|
|
4895
|
-
const candidatePath = join(currentDir, APP_IDENTITY_DIR, APP_IDENTITY_FILENAME);
|
|
4896
|
-
searchedPaths.push(candidatePath);
|
|
4897
|
-
if (await fileExists(candidatePath)) {
|
|
4898
|
-
return candidatePath;
|
|
4899
|
-
}
|
|
4900
|
-
const parentDir = dirname(currentDir);
|
|
4901
|
-
if (parentDir === currentDir) {
|
|
4902
|
-
throw AppIdentityError.notFound(searchedPaths);
|
|
4903
|
-
}
|
|
4904
|
-
currentDir = parentDir;
|
|
4905
|
-
}
|
|
4906
|
-
throw AppIdentityError.notFound(searchedPaths);
|
|
4907
|
-
}
|
|
4908
|
-
async function fileExists(path) {
|
|
4909
|
-
try {
|
|
4910
|
-
await access(path);
|
|
4911
|
-
return true;
|
|
4912
|
-
} catch {
|
|
4913
|
-
return false;
|
|
4914
|
-
}
|
|
4915
|
-
}
|
|
4916
|
-
var init_discovery = __esm({
|
|
4917
|
-
"src/appidentity/discovery.ts"() {
|
|
4918
|
-
init_constants();
|
|
4919
|
-
init_errors5();
|
|
4847
|
+
var init_correlation = __esm({
|
|
4848
|
+
"src/errors/correlation.ts"() {
|
|
4920
4849
|
}
|
|
4921
4850
|
});
|
|
4922
4851
|
|
|
4923
|
-
// src/
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
});
|
|
4930
|
-
function deepFreeze5(obj) {
|
|
4931
|
-
Object.freeze(obj);
|
|
4932
|
-
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
4933
|
-
const value = obj[prop];
|
|
4934
|
-
if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
|
|
4935
|
-
deepFreeze5(value);
|
|
4936
|
-
}
|
|
4937
|
-
});
|
|
4938
|
-
return obj;
|
|
4852
|
+
// src/errors/severity.ts
|
|
4853
|
+
function getDefaultSeverity() {
|
|
4854
|
+
return {
|
|
4855
|
+
name: Severity.MEDIUM,
|
|
4856
|
+
level: 2
|
|
4857
|
+
};
|
|
4939
4858
|
}
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
4859
|
+
var Severity, SEVERITY_LEVELS;
|
|
4860
|
+
var init_severity = __esm({
|
|
4861
|
+
"src/errors/severity.ts"() {
|
|
4862
|
+
Severity = {
|
|
4863
|
+
INFO: "info",
|
|
4864
|
+
LOW: "low",
|
|
4865
|
+
MEDIUM: "medium",
|
|
4866
|
+
HIGH: "high",
|
|
4867
|
+
CRITICAL: "critical"
|
|
4868
|
+
};
|
|
4869
|
+
SEVERITY_LEVELS = {
|
|
4870
|
+
info: 0,
|
|
4871
|
+
low: 1,
|
|
4872
|
+
medium: 2,
|
|
4873
|
+
high: 3,
|
|
4874
|
+
critical: 4
|
|
4875
|
+
};
|
|
4943
4876
|
}
|
|
4944
|
-
|
|
4945
|
-
|
|
4946
|
-
|
|
4947
|
-
|
|
4948
|
-
|
|
4877
|
+
});
|
|
4878
|
+
|
|
4879
|
+
// src/errors/serialization.ts
|
|
4880
|
+
function extractErrorMessage(error) {
|
|
4881
|
+
if (error instanceof Error) {
|
|
4882
|
+
return error.message;
|
|
4949
4883
|
}
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
startDir: options?.startDir
|
|
4953
|
-
});
|
|
4954
|
-
if (!discovery) {
|
|
4955
|
-
throw AppIdentityError.notFound([]);
|
|
4884
|
+
if (isErrorLike(error)) {
|
|
4885
|
+
return error.message;
|
|
4956
4886
|
}
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
content = await readFile(discovery.path, "utf-8");
|
|
4960
|
-
} catch (error) {
|
|
4961
|
-
throw AppIdentityError.readFailed(
|
|
4962
|
-
discovery.path,
|
|
4963
|
-
error instanceof Error ? error : new Error(String(error))
|
|
4964
|
-
);
|
|
4887
|
+
if (typeof error === "string") {
|
|
4888
|
+
return error;
|
|
4965
4889
|
}
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
discovery.path,
|
|
4972
|
-
error instanceof Error ? error : new Error(String(error))
|
|
4973
|
-
);
|
|
4890
|
+
return String(error);
|
|
4891
|
+
}
|
|
4892
|
+
function extractStackTrace(error) {
|
|
4893
|
+
if (error instanceof Error) {
|
|
4894
|
+
return error.stack;
|
|
4974
4895
|
}
|
|
4975
|
-
if (
|
|
4976
|
-
|
|
4977
|
-
if (!result.valid) {
|
|
4978
|
-
throw AppIdentityError.validationFailed(discovery.path, result.diagnostics);
|
|
4979
|
-
}
|
|
4896
|
+
if (isErrorLike(error) && typeof error.stack === "string") {
|
|
4897
|
+
return error.stack;
|
|
4980
4898
|
}
|
|
4981
|
-
|
|
4982
|
-
setCachedIdentity(identity);
|
|
4983
|
-
return identity;
|
|
4899
|
+
return void 0;
|
|
4984
4900
|
}
|
|
4985
|
-
|
|
4986
|
-
"
|
|
4987
|
-
|
|
4988
|
-
|
|
4989
|
-
|
|
4990
|
-
|
|
4991
|
-
init_errors5();
|
|
4901
|
+
function isErrorLike(value) {
|
|
4902
|
+
return typeof value === "object" && value !== null && "message" in value && typeof value.message === "string";
|
|
4903
|
+
}
|
|
4904
|
+
var init_serialization = __esm({
|
|
4905
|
+
"src/errors/serialization.ts"() {
|
|
4906
|
+
init_severity();
|
|
4992
4907
|
}
|
|
4993
4908
|
});
|
|
4994
|
-
|
|
4995
|
-
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
|
|
5001
|
-
|
|
5002
|
-
|
|
5003
|
-
|
|
5004
|
-
|
|
4909
|
+
|
|
4910
|
+
// src/errors/validators.ts
|
|
4911
|
+
async function validateErrorData(data) {
|
|
4912
|
+
return ErrorValidator.getInstance().validate(data);
|
|
4913
|
+
}
|
|
4914
|
+
var ErrorValidator;
|
|
4915
|
+
var init_validators2 = __esm({
|
|
4916
|
+
"src/errors/validators.ts"() {
|
|
4917
|
+
init_schema();
|
|
4918
|
+
ErrorValidator = class _ErrorValidator {
|
|
4919
|
+
static instance;
|
|
4920
|
+
validateFn = null;
|
|
4921
|
+
initPromise = null;
|
|
4922
|
+
initError = null;
|
|
4923
|
+
constructor() {
|
|
5005
4924
|
}
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
if (schema.description) {
|
|
5013
|
-
console.log(` Description: ${schema.description}`);
|
|
4925
|
+
/**
|
|
4926
|
+
* Get singleton instance
|
|
4927
|
+
*/
|
|
4928
|
+
static getInstance() {
|
|
4929
|
+
if (!_ErrorValidator.instance) {
|
|
4930
|
+
_ErrorValidator.instance = new _ErrorValidator();
|
|
5014
4931
|
}
|
|
5015
|
-
|
|
5016
|
-
}
|
|
5017
|
-
} catch (error) {
|
|
5018
|
-
console.error("Error listing schemas:", error.message);
|
|
5019
|
-
process.exit(1);
|
|
5020
|
-
}
|
|
5021
|
-
});
|
|
5022
|
-
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) => {
|
|
5023
|
-
try {
|
|
5024
|
-
const registry = getSchemaRegistry({
|
|
5025
|
-
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5026
|
-
});
|
|
5027
|
-
const schema = await registry.getSchema(cmdOptions.schemaId);
|
|
5028
|
-
console.log("Schema Details:\n");
|
|
5029
|
-
console.log(` ID: ${schema.id}`);
|
|
5030
|
-
console.log(` Format: ${schema.format}`);
|
|
5031
|
-
console.log(` Path: ${schema.path}`);
|
|
5032
|
-
console.log(` Relative Path: ${schema.relativePath}`);
|
|
5033
|
-
if (schema.version) {
|
|
5034
|
-
console.log(` Version: ${schema.version}`);
|
|
5035
|
-
}
|
|
5036
|
-
if (schema.description) {
|
|
5037
|
-
console.log(` Description: ${schema.description}`);
|
|
5038
|
-
}
|
|
5039
|
-
if (schema.schemaDraft) {
|
|
5040
|
-
console.log(` Schema Draft: ${schema.schemaDraft}`);
|
|
4932
|
+
return _ErrorValidator.instance;
|
|
5041
4933
|
}
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
4934
|
+
/**
|
|
4935
|
+
* Initialize validator (lazy load, async)
|
|
4936
|
+
*/
|
|
4937
|
+
async init() {
|
|
4938
|
+
if (this.validateFn !== null || this.initError !== null) {
|
|
4939
|
+
return;
|
|
4940
|
+
}
|
|
4941
|
+
if (this.initPromise) {
|
|
4942
|
+
return this.initPromise;
|
|
4943
|
+
}
|
|
4944
|
+
this.initPromise = (async () => {
|
|
4945
|
+
try {
|
|
4946
|
+
await compileSchemaById("pathfinder/v1.0.0/error-response");
|
|
4947
|
+
await compileSchemaById("assessment/v1.0.0/severity-definitions");
|
|
4948
|
+
this.validateFn = await compileSchemaById("error-handling/v1.0.0/error-response");
|
|
4949
|
+
} catch (err) {
|
|
4950
|
+
this.initError = err instanceof Error ? err : new Error(String(err));
|
|
4951
|
+
throw new Error(`Failed to initialize error validator: ${this.initError.message}`);
|
|
5060
4952
|
}
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
4953
|
+
})();
|
|
4954
|
+
return this.initPromise;
|
|
4955
|
+
}
|
|
4956
|
+
/**
|
|
4957
|
+
* Validate error data against schema
|
|
4958
|
+
*
|
|
4959
|
+
* @param data - Data to validate
|
|
4960
|
+
* @returns Promise resolving to true if valid, false otherwise
|
|
4961
|
+
* @throws {Error} If validator failed to initialize
|
|
4962
|
+
*/
|
|
4963
|
+
async validate(data) {
|
|
4964
|
+
if (this.validateFn === null) {
|
|
4965
|
+
await this.init();
|
|
5072
4966
|
}
|
|
5073
|
-
if (
|
|
5074
|
-
|
|
5075
|
-
process.exit(0);
|
|
5076
|
-
} else {
|
|
5077
|
-
console.log(`\u274C Validation failed (${result.source})`);
|
|
5078
|
-
console.log("\nDiagnostics:");
|
|
5079
|
-
console.log(formatDiagnostics(result.diagnostics));
|
|
5080
|
-
process.exit(1);
|
|
4967
|
+
if (this.initError) {
|
|
4968
|
+
throw this.initError;
|
|
5081
4969
|
}
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
4970
|
+
if (!this.validateFn) {
|
|
4971
|
+
throw new Error("Validator not initialized");
|
|
4972
|
+
}
|
|
4973
|
+
return this.validateFn(data);
|
|
5085
4974
|
}
|
|
5086
|
-
|
|
5087
|
-
|
|
5088
|
-
|
|
5089
|
-
|
|
5090
|
-
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
5094
|
-
|
|
5095
|
-
|
|
5096
|
-
} else {
|
|
5097
|
-
console.log("\u274C Schema is invalid");
|
|
5098
|
-
console.log("\nDiagnostics:");
|
|
5099
|
-
console.log(formatDiagnostics(result.diagnostics));
|
|
5100
|
-
process.exit(1);
|
|
4975
|
+
/**
|
|
4976
|
+
* Get validation errors from last validation
|
|
4977
|
+
*
|
|
4978
|
+
* @returns Validation errors or null
|
|
4979
|
+
*/
|
|
4980
|
+
getErrors() {
|
|
4981
|
+
if (!this.validateFn) {
|
|
4982
|
+
return null;
|
|
4983
|
+
}
|
|
4984
|
+
return this.validateFn.errors;
|
|
5101
4985
|
}
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
|
|
5106
|
-
|
|
5107
|
-
|
|
5108
|
-
try {
|
|
5109
|
-
const content = await readFile(file, "utf-8");
|
|
5110
|
-
const normalized = normalizeSchema(content, {
|
|
5111
|
-
compact: cmdOptions.compact
|
|
5112
|
-
});
|
|
5113
|
-
if (cmdOptions.output) {
|
|
5114
|
-
await writeFile(cmdOptions.output, normalized, "utf-8");
|
|
5115
|
-
console.log(`\u2705 Normalized schema written to ${cmdOptions.output}`);
|
|
5116
|
-
} else {
|
|
5117
|
-
console.log(normalized);
|
|
4986
|
+
/**
|
|
4987
|
+
* Reset validator state (for testing)
|
|
4988
|
+
* @internal
|
|
4989
|
+
*/
|
|
4990
|
+
static _reset() {
|
|
4991
|
+
_ErrorValidator.instance = new _ErrorValidator();
|
|
5118
4992
|
}
|
|
5119
|
-
}
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
|
|
5125
|
-
|
|
5126
|
-
|
|
5127
|
-
|
|
5128
|
-
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
4993
|
+
};
|
|
4994
|
+
}
|
|
4995
|
+
});
|
|
4996
|
+
|
|
4997
|
+
// src/errors/fulmen-error.ts
|
|
4998
|
+
function isFulmenErrorData(value) {
|
|
4999
|
+
return typeof value === "object" && value !== null && "code" in value && typeof value.code === "string" && "message" in value && typeof value.message === "string";
|
|
5000
|
+
}
|
|
5001
|
+
var FulmenError;
|
|
5002
|
+
var init_fulmen_error = __esm({
|
|
5003
|
+
"src/errors/fulmen-error.ts"() {
|
|
5004
|
+
init_serialization();
|
|
5005
|
+
init_severity();
|
|
5006
|
+
init_validators2();
|
|
5007
|
+
FulmenError = class _FulmenError extends Error {
|
|
5008
|
+
data;
|
|
5009
|
+
constructor(data) {
|
|
5010
|
+
super(data.message);
|
|
5011
|
+
this.name = "FulmenError";
|
|
5012
|
+
this.data = Object.freeze({ ...data });
|
|
5013
|
+
Error.captureStackTrace(this, _FulmenError);
|
|
5133
5014
|
}
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
}
|
|
5140
|
-
process.exit(result.equal ? 0 : 1);
|
|
5141
|
-
} catch (error) {
|
|
5142
|
-
console.error("Error comparing schemas:", error.message);
|
|
5143
|
-
process.exit(1);
|
|
5144
|
-
}
|
|
5145
|
-
});
|
|
5146
|
-
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(
|
|
5147
|
-
async (cmdOptions) => {
|
|
5148
|
-
try {
|
|
5149
|
-
const { exportSchema: exportSchema2 } = await Promise.resolve().then(() => (init_export(), export_exports));
|
|
5150
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5151
|
-
const result = await exportSchema2({
|
|
5152
|
-
schemaId: cmdOptions.schemaId,
|
|
5153
|
-
outPath: cmdOptions.out,
|
|
5154
|
-
includeProvenance: cmdOptions.provenance ?? true,
|
|
5155
|
-
validate: cmdOptions.validate ?? true,
|
|
5156
|
-
overwrite: cmdOptions.force ?? false,
|
|
5157
|
-
format: cmdOptions.format ?? "auto",
|
|
5158
|
-
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5159
|
-
});
|
|
5160
|
-
console.log("\u2705 Schema exported successfully");
|
|
5161
|
-
console.log(` Schema ID: ${result.schemaId}`);
|
|
5162
|
-
console.log(` Output: ${result.outPath}`);
|
|
5163
|
-
console.log(` Format: ${result.format}`);
|
|
5164
|
-
if (result.provenance) {
|
|
5165
|
-
console.log("\nProvenance:");
|
|
5166
|
-
console.log(` Crucible: ${result.provenance.crucible_version}`);
|
|
5167
|
-
console.log(` Library: ${result.provenance.library_version}`);
|
|
5168
|
-
if (result.provenance.revision) {
|
|
5169
|
-
console.log(` Revision: ${result.provenance.revision}`);
|
|
5170
|
-
}
|
|
5171
|
-
console.log(` Exported: ${result.provenance.exported_at}`);
|
|
5172
|
-
}
|
|
5173
|
-
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5174
|
-
} catch (error) {
|
|
5175
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5176
|
-
const { SchemaExportError: SchemaExportError2, SchemaValidationError: SchemaValidationError2, ExportErrorReason: ExportErrorReason2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
5177
|
-
console.error("\u274C Schema export failed:", error.message);
|
|
5178
|
-
if (error instanceof SchemaExportError2) {
|
|
5179
|
-
if (error.outPath) {
|
|
5180
|
-
console.error(` Output path: ${error.outPath}`);
|
|
5181
|
-
}
|
|
5182
|
-
switch (error.reason) {
|
|
5183
|
-
case ExportErrorReason2.FILE_EXISTS:
|
|
5184
|
-
case ExportErrorReason2.WRITE_FAILED:
|
|
5185
|
-
process.exit(exitCodes2.EXIT_FILE_WRITE_ERROR);
|
|
5186
|
-
break;
|
|
5187
|
-
case ExportErrorReason2.INVALID_FORMAT:
|
|
5188
|
-
process.exit(exitCodes2.EXIT_INVALID_ARGUMENT);
|
|
5189
|
-
break;
|
|
5190
|
-
default:
|
|
5191
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5192
|
-
}
|
|
5193
|
-
}
|
|
5194
|
-
if (error instanceof SchemaValidationError2) {
|
|
5195
|
-
const errorMsg = error.message.toLowerCase();
|
|
5196
|
-
if (errorMsg.includes("not found")) {
|
|
5197
|
-
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5198
|
-
}
|
|
5199
|
-
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5200
|
-
}
|
|
5201
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5202
|
-
}
|
|
5203
|
-
}
|
|
5204
|
-
);
|
|
5205
|
-
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) => {
|
|
5206
|
-
try {
|
|
5207
|
-
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5208
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5209
|
-
const identity = await loadIdentity2({ path: cmdOptions.path });
|
|
5210
|
-
if (cmdOptions.json) {
|
|
5211
|
-
console.log(JSON.stringify(identity, null, 2));
|
|
5212
|
-
} else {
|
|
5213
|
-
console.log("Application Identity:\n");
|
|
5214
|
-
console.log(` Binary Name: ${identity.app.binary_name}`);
|
|
5215
|
-
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5216
|
-
console.log(` Env Prefix: ${identity.app.env_prefix}`);
|
|
5217
|
-
console.log(` Config Name: ${identity.app.config_name}`);
|
|
5218
|
-
console.log(` Description: ${identity.app.description}`);
|
|
5219
|
-
if (identity.metadata) {
|
|
5220
|
-
console.log("\nMetadata:");
|
|
5221
|
-
if (identity.metadata.license) {
|
|
5222
|
-
console.log(` License: ${identity.metadata.license}`);
|
|
5223
|
-
}
|
|
5224
|
-
if (identity.metadata.repository_category) {
|
|
5225
|
-
console.log(` Category: ${identity.metadata.repository_category}`);
|
|
5226
|
-
}
|
|
5227
|
-
if (identity.metadata.telemetry_namespace) {
|
|
5228
|
-
console.log(` Telemetry: ${identity.metadata.telemetry_namespace}`);
|
|
5229
|
-
}
|
|
5230
|
-
if (identity.metadata.project_url) {
|
|
5231
|
-
console.log(` Project URL: ${identity.metadata.project_url}`);
|
|
5232
|
-
}
|
|
5233
|
-
}
|
|
5234
|
-
}
|
|
5235
|
-
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5236
|
-
} catch (error) {
|
|
5237
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5238
|
-
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5239
|
-
console.error("\u274C Failed to load identity:", error.message);
|
|
5240
|
-
if (error instanceof AppIdentityError2) {
|
|
5241
|
-
if (error.message.includes("not found")) {
|
|
5242
|
-
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5243
|
-
}
|
|
5244
|
-
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5245
|
-
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5246
|
-
}
|
|
5247
|
-
}
|
|
5248
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5249
|
-
}
|
|
5250
|
-
});
|
|
5251
|
-
program.command("identity-validate").description("Validate application identity against schema").argument("[file]", "Path to app.yaml (defaults to discovery)").action(async (file) => {
|
|
5252
|
-
try {
|
|
5253
|
-
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5254
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5255
|
-
console.log("Validating application identity...");
|
|
5256
|
-
const identity = await loadIdentity2({ path: file });
|
|
5257
|
-
console.log("\u2705 Identity is valid");
|
|
5258
|
-
console.log(` Binary: ${identity.app.binary_name}`);
|
|
5259
|
-
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5260
|
-
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5261
|
-
} catch (error) {
|
|
5262
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5263
|
-
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5264
|
-
console.error("\u274C Identity validation failed:", error.message);
|
|
5265
|
-
if (error instanceof AppIdentityError2) {
|
|
5266
|
-
if (error.message.includes("not found")) {
|
|
5267
|
-
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5268
|
-
}
|
|
5269
|
-
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5270
|
-
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5271
|
-
}
|
|
5272
|
-
}
|
|
5273
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5274
|
-
}
|
|
5275
|
-
});
|
|
5276
|
-
return program;
|
|
5277
|
-
}
|
|
5278
|
-
var init_cli = __esm({
|
|
5279
|
-
"src/schema/cli.ts"() {
|
|
5280
|
-
init_goneat_bridge();
|
|
5281
|
-
init_normalizer();
|
|
5282
|
-
init_registry();
|
|
5283
|
-
init_utils();
|
|
5284
|
-
init_validator();
|
|
5285
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
5286
|
-
const program = createCLI();
|
|
5287
|
-
program.parse(process.argv);
|
|
5288
|
-
}
|
|
5289
|
-
}
|
|
5290
|
-
});
|
|
5291
|
-
|
|
5292
|
-
// src/schema/index.ts
|
|
5293
|
-
var init_schema = __esm({
|
|
5294
|
-
"src/schema/index.ts"() {
|
|
5295
|
-
init_cli();
|
|
5296
|
-
init_errors();
|
|
5297
|
-
init_export();
|
|
5298
|
-
init_goneat_bridge();
|
|
5299
|
-
init_normalizer();
|
|
5300
|
-
init_registry();
|
|
5301
|
-
init_utils();
|
|
5302
|
-
init_validator();
|
|
5303
|
-
}
|
|
5304
|
-
});
|
|
5305
|
-
|
|
5306
|
-
// src/errors/validators.ts
|
|
5307
|
-
async function validateErrorData(data) {
|
|
5308
|
-
return ErrorValidator.getInstance().validate(data);
|
|
5309
|
-
}
|
|
5310
|
-
var ErrorValidator;
|
|
5311
|
-
var init_validators2 = __esm({
|
|
5312
|
-
"src/errors/validators.ts"() {
|
|
5313
|
-
init_schema();
|
|
5314
|
-
ErrorValidator = class _ErrorValidator {
|
|
5315
|
-
static instance;
|
|
5316
|
-
validateFn = null;
|
|
5317
|
-
initPromise = null;
|
|
5318
|
-
initError = null;
|
|
5319
|
-
constructor() {
|
|
5320
|
-
}
|
|
5321
|
-
/**
|
|
5322
|
-
* Get singleton instance
|
|
5323
|
-
*/
|
|
5324
|
-
static getInstance() {
|
|
5325
|
-
if (!_ErrorValidator.instance) {
|
|
5326
|
-
_ErrorValidator.instance = new _ErrorValidator();
|
|
5327
|
-
}
|
|
5328
|
-
return _ErrorValidator.instance;
|
|
5329
|
-
}
|
|
5330
|
-
/**
|
|
5331
|
-
* Initialize validator (lazy load, async)
|
|
5332
|
-
*/
|
|
5333
|
-
async init() {
|
|
5334
|
-
if (this.validateFn !== null || this.initError !== null) {
|
|
5335
|
-
return;
|
|
5336
|
-
}
|
|
5337
|
-
if (this.initPromise) {
|
|
5338
|
-
return this.initPromise;
|
|
5339
|
-
}
|
|
5340
|
-
this.initPromise = (async () => {
|
|
5341
|
-
try {
|
|
5342
|
-
await compileSchemaById("pathfinder/v1.0.0/error-response");
|
|
5343
|
-
await compileSchemaById("assessment/v1.0.0/severity-definitions");
|
|
5344
|
-
this.validateFn = await compileSchemaById("error-handling/v1.0.0/error-response");
|
|
5345
|
-
} catch (err) {
|
|
5346
|
-
this.initError = err instanceof Error ? err : new Error(String(err));
|
|
5347
|
-
throw new Error(`Failed to initialize error validator: ${this.initError.message}`);
|
|
5348
|
-
}
|
|
5349
|
-
})();
|
|
5350
|
-
return this.initPromise;
|
|
5351
|
-
}
|
|
5352
|
-
/**
|
|
5353
|
-
* Validate error data against schema
|
|
5354
|
-
*
|
|
5355
|
-
* @param data - Data to validate
|
|
5356
|
-
* @returns Promise resolving to true if valid, false otherwise
|
|
5357
|
-
* @throws {Error} If validator failed to initialize
|
|
5358
|
-
*/
|
|
5359
|
-
async validate(data) {
|
|
5360
|
-
if (this.validateFn === null) {
|
|
5361
|
-
await this.init();
|
|
5362
|
-
}
|
|
5363
|
-
if (this.initError) {
|
|
5364
|
-
throw this.initError;
|
|
5365
|
-
}
|
|
5366
|
-
if (!this.validateFn) {
|
|
5367
|
-
throw new Error("Validator not initialized");
|
|
5368
|
-
}
|
|
5369
|
-
return this.validateFn(data);
|
|
5370
|
-
}
|
|
5371
|
-
/**
|
|
5372
|
-
* Get validation errors from last validation
|
|
5373
|
-
*
|
|
5374
|
-
* @returns Validation errors or null
|
|
5375
|
-
*/
|
|
5376
|
-
getErrors() {
|
|
5377
|
-
if (!this.validateFn) {
|
|
5378
|
-
return null;
|
|
5379
|
-
}
|
|
5380
|
-
return this.validateFn.errors;
|
|
5381
|
-
}
|
|
5382
|
-
/**
|
|
5383
|
-
* Reset validator state (for testing)
|
|
5384
|
-
* @internal
|
|
5385
|
-
*/
|
|
5386
|
-
static _reset() {
|
|
5387
|
-
_ErrorValidator.instance = new _ErrorValidator();
|
|
5388
|
-
}
|
|
5389
|
-
};
|
|
5390
|
-
}
|
|
5391
|
-
});
|
|
5392
|
-
|
|
5393
|
-
// src/errors/fulmen-error.ts
|
|
5394
|
-
function isFulmenErrorData(value) {
|
|
5395
|
-
return typeof value === "object" && value !== null && "code" in value && typeof value.code === "string" && "message" in value && typeof value.message === "string";
|
|
5396
|
-
}
|
|
5397
|
-
var FulmenError;
|
|
5398
|
-
var init_fulmen_error = __esm({
|
|
5399
|
-
"src/errors/fulmen-error.ts"() {
|
|
5400
|
-
init_serialization();
|
|
5401
|
-
init_severity();
|
|
5402
|
-
init_validators2();
|
|
5403
|
-
FulmenError = class _FulmenError extends Error {
|
|
5404
|
-
data;
|
|
5405
|
-
constructor(data) {
|
|
5406
|
-
super(data.message);
|
|
5407
|
-
this.name = "FulmenError";
|
|
5408
|
-
this.data = Object.freeze({ ...data });
|
|
5409
|
-
Error.captureStackTrace(this, _FulmenError);
|
|
5410
|
-
}
|
|
5411
|
-
/**
|
|
5412
|
-
* Serialize to JSON (schema-compliant)
|
|
5413
|
-
*/
|
|
5414
|
-
toJSON() {
|
|
5415
|
-
return this.data;
|
|
5015
|
+
/**
|
|
5016
|
+
* Serialize to JSON (schema-compliant)
|
|
5017
|
+
*/
|
|
5018
|
+
toJSON() {
|
|
5019
|
+
return this.data;
|
|
5416
5020
|
}
|
|
5417
5021
|
/**
|
|
5418
5022
|
* Check equality with another FulmenError
|
|
@@ -5666,12 +5270,568 @@ ${cause.message}`;
|
|
|
5666
5270
|
${cause.message}`;
|
|
5667
5271
|
return new _AppIdentityError(message, path, cause);
|
|
5668
5272
|
}
|
|
5669
|
-
|
|
5273
|
+
/**
|
|
5274
|
+
* Create error for embedded identity already registered
|
|
5275
|
+
*
|
|
5276
|
+
* Uses first-wins semantics - once registered, cannot be replaced
|
|
5277
|
+
*/
|
|
5278
|
+
static alreadyRegistered() {
|
|
5279
|
+
const message = "Embedded identity already registered. Registration uses first-wins semantics and cannot be replaced.";
|
|
5280
|
+
return new _AppIdentityError(message);
|
|
5281
|
+
}
|
|
5282
|
+
/**
|
|
5283
|
+
* Create error for embedded identity YAML parsing failure
|
|
5284
|
+
*/
|
|
5285
|
+
static embeddedParseFailed(cause) {
|
|
5286
|
+
const message = `Failed to parse embedded identity YAML: ${cause.message}`;
|
|
5287
|
+
return new _AppIdentityError(message, void 0, cause);
|
|
5288
|
+
}
|
|
5289
|
+
/**
|
|
5290
|
+
* Create error for embedded identity schema validation failure
|
|
5291
|
+
*/
|
|
5292
|
+
static embeddedValidationFailed(diagnostics) {
|
|
5293
|
+
const errorCount = diagnostics.filter((d) => d.severity === "ERROR").length;
|
|
5294
|
+
const warningCount = diagnostics.filter((d) => d.severity === "WARN").length;
|
|
5295
|
+
let message = "Invalid embedded identity\n";
|
|
5296
|
+
message += `Validation errors: ${errorCount} error(s), ${warningCount} warning(s)
|
|
5297
|
+
`;
|
|
5298
|
+
const displayDiagnostics = diagnostics.slice(0, 3);
|
|
5299
|
+
for (const diag of displayDiagnostics) {
|
|
5300
|
+
message += ` - ${diag.message}`;
|
|
5301
|
+
if (diag.pointer) {
|
|
5302
|
+
message += ` at ${diag.pointer}`;
|
|
5303
|
+
}
|
|
5304
|
+
message += "\n";
|
|
5305
|
+
}
|
|
5306
|
+
if (diagnostics.length > 3) {
|
|
5307
|
+
message += ` ... and ${diagnostics.length - 3} more
|
|
5308
|
+
`;
|
|
5309
|
+
}
|
|
5310
|
+
return new _AppIdentityError(message);
|
|
5311
|
+
}
|
|
5312
|
+
};
|
|
5313
|
+
}
|
|
5314
|
+
});
|
|
5315
|
+
async function discoverIdentityPath(options) {
|
|
5316
|
+
if (options?.path) {
|
|
5317
|
+
const exists = await fileExists(options.path);
|
|
5318
|
+
if (!exists) {
|
|
5319
|
+
throw AppIdentityError.notFound([options.path]);
|
|
5320
|
+
}
|
|
5321
|
+
return { path: options.path, source: "explicit" };
|
|
5322
|
+
}
|
|
5323
|
+
const envPath = process.env[APP_IDENTITY_ENV_VAR];
|
|
5324
|
+
if (envPath) {
|
|
5325
|
+
const exists = await fileExists(envPath);
|
|
5326
|
+
if (!exists) {
|
|
5327
|
+
throw AppIdentityError.envOverrideMissing(envPath);
|
|
5328
|
+
}
|
|
5329
|
+
return { path: envPath, source: "env" };
|
|
5330
|
+
}
|
|
5331
|
+
const startDir = options?.startDir || process.cwd();
|
|
5332
|
+
const result = await searchAncestors(startDir);
|
|
5333
|
+
if (result) {
|
|
5334
|
+
return { path: result, source: "ancestor" };
|
|
5335
|
+
}
|
|
5336
|
+
return null;
|
|
5337
|
+
}
|
|
5338
|
+
async function searchAncestors(startDir) {
|
|
5339
|
+
let currentDir = startDir;
|
|
5340
|
+
const searchedPaths = [];
|
|
5341
|
+
for (let i = 0; i < MAX_ANCESTOR_SEARCH_DEPTH; i++) {
|
|
5342
|
+
const candidatePath = join(currentDir, APP_IDENTITY_DIR, APP_IDENTITY_FILENAME);
|
|
5343
|
+
searchedPaths.push(candidatePath);
|
|
5344
|
+
if (await fileExists(candidatePath)) {
|
|
5345
|
+
return candidatePath;
|
|
5346
|
+
}
|
|
5347
|
+
const parentDir = dirname(currentDir);
|
|
5348
|
+
if (parentDir === currentDir) {
|
|
5349
|
+
throw AppIdentityError.notFound(searchedPaths);
|
|
5350
|
+
}
|
|
5351
|
+
currentDir = parentDir;
|
|
5352
|
+
}
|
|
5353
|
+
throw AppIdentityError.notFound(searchedPaths);
|
|
5354
|
+
}
|
|
5355
|
+
async function fileExists(path) {
|
|
5356
|
+
try {
|
|
5357
|
+
await access(path);
|
|
5358
|
+
return true;
|
|
5359
|
+
} catch {
|
|
5360
|
+
return false;
|
|
5361
|
+
}
|
|
5362
|
+
}
|
|
5363
|
+
var init_discovery = __esm({
|
|
5364
|
+
"src/appidentity/discovery.ts"() {
|
|
5365
|
+
init_constants();
|
|
5366
|
+
init_errors5();
|
|
5367
|
+
}
|
|
5368
|
+
});
|
|
5369
|
+
|
|
5370
|
+
// src/appidentity/loader.ts
|
|
5371
|
+
var loader_exports = {};
|
|
5372
|
+
__export(loader_exports, {
|
|
5373
|
+
clearIdentityCache: () => clearIdentityCache,
|
|
5374
|
+
getCachedIdentity: () => getCachedIdentity,
|
|
5375
|
+
loadIdentity: () => loadIdentity
|
|
5376
|
+
});
|
|
5377
|
+
function deepFreeze5(obj) {
|
|
5378
|
+
Object.freeze(obj);
|
|
5379
|
+
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
5380
|
+
const value = obj[prop];
|
|
5381
|
+
if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
|
|
5382
|
+
deepFreeze5(value);
|
|
5383
|
+
}
|
|
5384
|
+
});
|
|
5385
|
+
return obj;
|
|
5386
|
+
}
|
|
5387
|
+
async function loadIdentity(options) {
|
|
5388
|
+
if (options?.identity) {
|
|
5389
|
+
return deepFreeze5(structuredClone(options.identity));
|
|
5390
|
+
}
|
|
5391
|
+
if (!options?.skipCache) {
|
|
5392
|
+
const cached = getCachedIdentity();
|
|
5393
|
+
if (cached) {
|
|
5394
|
+
return cached;
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
let discovery;
|
|
5398
|
+
try {
|
|
5399
|
+
discovery = await discoverIdentityPath({
|
|
5400
|
+
path: options?.path,
|
|
5401
|
+
startDir: options?.startDir
|
|
5402
|
+
});
|
|
5403
|
+
} catch (error) {
|
|
5404
|
+
const hasExplicitPath = Boolean(options?.path);
|
|
5405
|
+
const hasEnvOverride = Boolean(process.env[APP_IDENTITY_ENV_VAR]);
|
|
5406
|
+
if (!hasExplicitPath && !hasEnvOverride && error instanceof AppIdentityError) {
|
|
5407
|
+
const embedded = getEmbeddedIdentity();
|
|
5408
|
+
if (embedded) {
|
|
5409
|
+
setCachedIdentity(embedded);
|
|
5410
|
+
return embedded;
|
|
5411
|
+
}
|
|
5412
|
+
}
|
|
5413
|
+
throw error;
|
|
5414
|
+
}
|
|
5415
|
+
if (!discovery) {
|
|
5416
|
+
const embedded = getEmbeddedIdentity();
|
|
5417
|
+
if (embedded) {
|
|
5418
|
+
setCachedIdentity(embedded);
|
|
5419
|
+
return embedded;
|
|
5420
|
+
}
|
|
5421
|
+
throw AppIdentityError.notFound([]);
|
|
5422
|
+
}
|
|
5423
|
+
let content;
|
|
5424
|
+
try {
|
|
5425
|
+
content = await readFile(discovery.path, "utf-8");
|
|
5426
|
+
} catch (error) {
|
|
5427
|
+
throw AppIdentityError.readFailed(
|
|
5428
|
+
discovery.path,
|
|
5429
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5430
|
+
);
|
|
5431
|
+
}
|
|
5432
|
+
let parsed;
|
|
5433
|
+
try {
|
|
5434
|
+
parsed = parse(content);
|
|
5435
|
+
} catch (error) {
|
|
5436
|
+
throw AppIdentityError.parseFailed(
|
|
5437
|
+
discovery.path,
|
|
5438
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5439
|
+
);
|
|
5440
|
+
}
|
|
5441
|
+
if (!options?.skipValidation) {
|
|
5442
|
+
const result = await validateDataBySchemaId(parsed, APP_IDENTITY_SCHEMA_ID);
|
|
5443
|
+
if (!result.valid) {
|
|
5444
|
+
throw AppIdentityError.validationFailed(discovery.path, result.diagnostics);
|
|
5445
|
+
}
|
|
5446
|
+
}
|
|
5447
|
+
const identity = deepFreeze5(structuredClone(parsed));
|
|
5448
|
+
setCachedIdentity(identity);
|
|
5449
|
+
return identity;
|
|
5450
|
+
}
|
|
5451
|
+
var init_loader2 = __esm({
|
|
5452
|
+
"src/appidentity/loader.ts"() {
|
|
5453
|
+
init_schema();
|
|
5454
|
+
init_cache();
|
|
5455
|
+
init_constants();
|
|
5456
|
+
init_discovery();
|
|
5457
|
+
init_embedded();
|
|
5458
|
+
init_errors5();
|
|
5459
|
+
}
|
|
5460
|
+
});
|
|
5461
|
+
function createCLI(options = {}) {
|
|
5462
|
+
const program = new Command();
|
|
5463
|
+
program.name("tsfulmen-schema").description("Schema validation and discovery CLI for Fulmen (developer tool)").version("0.1.0");
|
|
5464
|
+
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) => {
|
|
5465
|
+
try {
|
|
5466
|
+
const schemas = await listSchemas(prefix, {
|
|
5467
|
+
baseDir: cmdOptions?.baseDir || options.baseDir
|
|
5468
|
+
});
|
|
5469
|
+
if (schemas.length === 0) {
|
|
5470
|
+
console.log("No schemas found");
|
|
5471
|
+
return;
|
|
5472
|
+
}
|
|
5473
|
+
console.log(`Found ${schemas.length} schema(s):
|
|
5474
|
+
`);
|
|
5475
|
+
for (const schema of schemas) {
|
|
5476
|
+
console.log(` ${schema.id}`);
|
|
5477
|
+
console.log(` Format: ${schema.format}`);
|
|
5478
|
+
console.log(` Path: ${schema.relativePath}`);
|
|
5479
|
+
if (schema.description) {
|
|
5480
|
+
console.log(` Description: ${schema.description}`);
|
|
5481
|
+
}
|
|
5482
|
+
console.log();
|
|
5483
|
+
}
|
|
5484
|
+
} catch (error) {
|
|
5485
|
+
console.error("Error listing schemas:", error.message);
|
|
5486
|
+
process.exit(1);
|
|
5487
|
+
}
|
|
5488
|
+
});
|
|
5489
|
+
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) => {
|
|
5490
|
+
try {
|
|
5491
|
+
const registry = getSchemaRegistry({
|
|
5492
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5493
|
+
});
|
|
5494
|
+
const schema = await registry.getSchema(cmdOptions.schemaId);
|
|
5495
|
+
console.log("Schema Details:\n");
|
|
5496
|
+
console.log(` ID: ${schema.id}`);
|
|
5497
|
+
console.log(` Format: ${schema.format}`);
|
|
5498
|
+
console.log(` Path: ${schema.path}`);
|
|
5499
|
+
console.log(` Relative Path: ${schema.relativePath}`);
|
|
5500
|
+
if (schema.version) {
|
|
5501
|
+
console.log(` Version: ${schema.version}`);
|
|
5502
|
+
}
|
|
5503
|
+
if (schema.description) {
|
|
5504
|
+
console.log(` Description: ${schema.description}`);
|
|
5505
|
+
}
|
|
5506
|
+
if (schema.schemaDraft) {
|
|
5507
|
+
console.log(` Schema Draft: ${schema.schemaDraft}`);
|
|
5508
|
+
}
|
|
5509
|
+
const content = await readFile(schema.path, "utf-8");
|
|
5510
|
+
console.log("\nSchema Content:");
|
|
5511
|
+
console.log(content);
|
|
5512
|
+
} catch (error) {
|
|
5513
|
+
console.error("Error showing schema:", error.message);
|
|
5514
|
+
process.exit(1);
|
|
5515
|
+
}
|
|
5516
|
+
});
|
|
5517
|
+
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(
|
|
5518
|
+
async (file, cmdOptions) => {
|
|
5519
|
+
try {
|
|
5520
|
+
let result;
|
|
5521
|
+
if (cmdOptions.useGoneat) {
|
|
5522
|
+
const available = await isGoneatAvailable(cmdOptions.goneatPath);
|
|
5523
|
+
if (!available) {
|
|
5524
|
+
console.error("\u274C goneat not available. Install goneat or remove --use-goneat flag.");
|
|
5525
|
+
console.error(" AJV validation (default) works without external dependencies.");
|
|
5526
|
+
process.exit(1);
|
|
5527
|
+
}
|
|
5528
|
+
const registry = getSchemaRegistry({
|
|
5529
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5530
|
+
});
|
|
5531
|
+
const schema = await registry.getSchema(cmdOptions.schemaId);
|
|
5532
|
+
console.log("Using goneat validation...");
|
|
5533
|
+
result = await runGoneatValidation(schema.path, file, cmdOptions.goneatPath);
|
|
5534
|
+
} else {
|
|
5535
|
+
console.log("Using AJV validation...");
|
|
5536
|
+
result = await validateFileBySchemaId(file, cmdOptions.schemaId, {
|
|
5537
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5538
|
+
});
|
|
5539
|
+
}
|
|
5540
|
+
if (result.valid) {
|
|
5541
|
+
console.log(`\u2705 Validation passed (${result.source})`);
|
|
5542
|
+
process.exit(0);
|
|
5543
|
+
} else {
|
|
5544
|
+
console.log(`\u274C Validation failed (${result.source})`);
|
|
5545
|
+
console.log("\nDiagnostics:");
|
|
5546
|
+
console.log(formatDiagnostics(result.diagnostics));
|
|
5547
|
+
process.exit(1);
|
|
5548
|
+
}
|
|
5549
|
+
} catch (error) {
|
|
5550
|
+
console.error("Error validating file:", error.message);
|
|
5551
|
+
process.exit(1);
|
|
5552
|
+
}
|
|
5553
|
+
}
|
|
5554
|
+
);
|
|
5555
|
+
program.command("validate-schema").description("Validate a schema file itself").argument("<file>", "Schema file to validate").action(async (file) => {
|
|
5556
|
+
try {
|
|
5557
|
+
const content = await readFile(file, "utf-8");
|
|
5558
|
+
const { validateSchema: validateSchema2 } = await Promise.resolve().then(() => (init_validator(), validator_exports));
|
|
5559
|
+
const result = await validateSchema2(content);
|
|
5560
|
+
if (result.valid) {
|
|
5561
|
+
console.log("\u2705 Schema is valid");
|
|
5562
|
+
process.exit(0);
|
|
5563
|
+
} else {
|
|
5564
|
+
console.log("\u274C Schema is invalid");
|
|
5565
|
+
console.log("\nDiagnostics:");
|
|
5566
|
+
console.log(formatDiagnostics(result.diagnostics));
|
|
5567
|
+
process.exit(1);
|
|
5568
|
+
}
|
|
5569
|
+
} catch (error) {
|
|
5570
|
+
console.error("Error validating schema:", error.message);
|
|
5571
|
+
process.exit(1);
|
|
5572
|
+
}
|
|
5573
|
+
});
|
|
5574
|
+
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) => {
|
|
5575
|
+
try {
|
|
5576
|
+
const content = await readFile(file, "utf-8");
|
|
5577
|
+
const normalized = normalizeSchema(content, {
|
|
5578
|
+
compact: cmdOptions.compact
|
|
5579
|
+
});
|
|
5580
|
+
if (cmdOptions.output) {
|
|
5581
|
+
await writeFile(cmdOptions.output, normalized, "utf-8");
|
|
5582
|
+
console.log(`\u2705 Normalized schema written to ${cmdOptions.output}`);
|
|
5583
|
+
} else {
|
|
5584
|
+
console.log(normalized);
|
|
5585
|
+
}
|
|
5586
|
+
} catch (error) {
|
|
5587
|
+
console.error("Error normalizing schema:", error.message);
|
|
5588
|
+
process.exit(1);
|
|
5589
|
+
}
|
|
5590
|
+
});
|
|
5591
|
+
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) => {
|
|
5592
|
+
try {
|
|
5593
|
+
const content1 = await readFile(file1, "utf-8");
|
|
5594
|
+
const content2 = await readFile(file2, "utf-8");
|
|
5595
|
+
const result = compareSchemas(content1, content2);
|
|
5596
|
+
if (result.equal) {
|
|
5597
|
+
console.log("\u2705 Schemas are semantically equal");
|
|
5598
|
+
} else {
|
|
5599
|
+
console.log("\u274C Schemas differ");
|
|
5600
|
+
}
|
|
5601
|
+
if (cmdOptions.showNormalized) {
|
|
5602
|
+
console.log("\nNormalized Schema 1:");
|
|
5603
|
+
console.log(result.normalizedA);
|
|
5604
|
+
console.log("\nNormalized Schema 2:");
|
|
5605
|
+
console.log(result.normalizedB);
|
|
5606
|
+
}
|
|
5607
|
+
process.exit(result.equal ? 0 : 1);
|
|
5608
|
+
} catch (error) {
|
|
5609
|
+
console.error("Error comparing schemas:", error.message);
|
|
5610
|
+
process.exit(1);
|
|
5611
|
+
}
|
|
5612
|
+
});
|
|
5613
|
+
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(
|
|
5614
|
+
async (cmdOptions) => {
|
|
5615
|
+
try {
|
|
5616
|
+
const { exportSchema: exportSchema2 } = await Promise.resolve().then(() => (init_export(), export_exports));
|
|
5617
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5618
|
+
const result = await exportSchema2({
|
|
5619
|
+
schemaId: cmdOptions.schemaId,
|
|
5620
|
+
outPath: cmdOptions.out,
|
|
5621
|
+
includeProvenance: cmdOptions.provenance ?? true,
|
|
5622
|
+
validate: cmdOptions.validate ?? true,
|
|
5623
|
+
overwrite: cmdOptions.force ?? false,
|
|
5624
|
+
format: cmdOptions.format ?? "auto",
|
|
5625
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5626
|
+
});
|
|
5627
|
+
console.log("\u2705 Schema exported successfully");
|
|
5628
|
+
console.log(` Schema ID: ${result.schemaId}`);
|
|
5629
|
+
console.log(` Output: ${result.outPath}`);
|
|
5630
|
+
console.log(` Format: ${result.format}`);
|
|
5631
|
+
if (result.provenance) {
|
|
5632
|
+
console.log("\nProvenance:");
|
|
5633
|
+
console.log(` Crucible: ${result.provenance.crucible_version}`);
|
|
5634
|
+
console.log(` Library: ${result.provenance.library_version}`);
|
|
5635
|
+
if (result.provenance.revision) {
|
|
5636
|
+
console.log(` Revision: ${result.provenance.revision}`);
|
|
5637
|
+
}
|
|
5638
|
+
console.log(` Exported: ${result.provenance.exported_at}`);
|
|
5639
|
+
}
|
|
5640
|
+
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5641
|
+
} catch (error) {
|
|
5642
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5643
|
+
const { SchemaExportError: SchemaExportError2, SchemaValidationError: SchemaValidationError2, ExportErrorReason: ExportErrorReason2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
5644
|
+
console.error("\u274C Schema export failed:", error.message);
|
|
5645
|
+
if (error instanceof SchemaExportError2) {
|
|
5646
|
+
if (error.outPath) {
|
|
5647
|
+
console.error(` Output path: ${error.outPath}`);
|
|
5648
|
+
}
|
|
5649
|
+
switch (error.reason) {
|
|
5650
|
+
case ExportErrorReason2.FILE_EXISTS:
|
|
5651
|
+
case ExportErrorReason2.WRITE_FAILED:
|
|
5652
|
+
process.exit(exitCodes2.EXIT_FILE_WRITE_ERROR);
|
|
5653
|
+
break;
|
|
5654
|
+
case ExportErrorReason2.INVALID_FORMAT:
|
|
5655
|
+
process.exit(exitCodes2.EXIT_INVALID_ARGUMENT);
|
|
5656
|
+
break;
|
|
5657
|
+
default:
|
|
5658
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5659
|
+
}
|
|
5660
|
+
}
|
|
5661
|
+
if (error instanceof SchemaValidationError2) {
|
|
5662
|
+
const errorMsg = error.message.toLowerCase();
|
|
5663
|
+
if (errorMsg.includes("not found")) {
|
|
5664
|
+
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5665
|
+
}
|
|
5666
|
+
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5667
|
+
}
|
|
5668
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5669
|
+
}
|
|
5670
|
+
}
|
|
5671
|
+
);
|
|
5672
|
+
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) => {
|
|
5673
|
+
try {
|
|
5674
|
+
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5675
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5676
|
+
const identity = await loadIdentity2({ path: cmdOptions.path });
|
|
5677
|
+
if (cmdOptions.json) {
|
|
5678
|
+
console.log(JSON.stringify(identity, null, 2));
|
|
5679
|
+
} else {
|
|
5680
|
+
console.log("Application Identity:\n");
|
|
5681
|
+
console.log(` Binary Name: ${identity.app.binary_name}`);
|
|
5682
|
+
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5683
|
+
console.log(` Env Prefix: ${identity.app.env_prefix}`);
|
|
5684
|
+
console.log(` Config Name: ${identity.app.config_name}`);
|
|
5685
|
+
console.log(` Description: ${identity.app.description}`);
|
|
5686
|
+
if (identity.metadata) {
|
|
5687
|
+
console.log("\nMetadata:");
|
|
5688
|
+
if (identity.metadata.license) {
|
|
5689
|
+
console.log(` License: ${identity.metadata.license}`);
|
|
5690
|
+
}
|
|
5691
|
+
if (identity.metadata.repository_category) {
|
|
5692
|
+
console.log(` Category: ${identity.metadata.repository_category}`);
|
|
5693
|
+
}
|
|
5694
|
+
if (identity.metadata.telemetry_namespace) {
|
|
5695
|
+
console.log(` Telemetry: ${identity.metadata.telemetry_namespace}`);
|
|
5696
|
+
}
|
|
5697
|
+
if (identity.metadata.project_url) {
|
|
5698
|
+
console.log(` Project URL: ${identity.metadata.project_url}`);
|
|
5699
|
+
}
|
|
5700
|
+
}
|
|
5701
|
+
}
|
|
5702
|
+
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5703
|
+
} catch (error) {
|
|
5704
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5705
|
+
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5706
|
+
console.error("\u274C Failed to load identity:", error.message);
|
|
5707
|
+
if (error instanceof AppIdentityError2) {
|
|
5708
|
+
if (error.message.includes("not found")) {
|
|
5709
|
+
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5710
|
+
}
|
|
5711
|
+
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5712
|
+
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5713
|
+
}
|
|
5714
|
+
}
|
|
5715
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5716
|
+
}
|
|
5717
|
+
});
|
|
5718
|
+
program.command("identity-validate").description("Validate application identity against schema").argument("[file]", "Path to app.yaml (defaults to discovery)").action(async (file) => {
|
|
5719
|
+
try {
|
|
5720
|
+
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5721
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5722
|
+
console.log("Validating application identity...");
|
|
5723
|
+
const identity = await loadIdentity2({ path: file });
|
|
5724
|
+
console.log("\u2705 Identity is valid");
|
|
5725
|
+
console.log(` Binary: ${identity.app.binary_name}`);
|
|
5726
|
+
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5727
|
+
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5728
|
+
} catch (error) {
|
|
5729
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5730
|
+
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5731
|
+
console.error("\u274C Identity validation failed:", error.message);
|
|
5732
|
+
if (error instanceof AppIdentityError2) {
|
|
5733
|
+
if (error.message.includes("not found")) {
|
|
5734
|
+
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5735
|
+
}
|
|
5736
|
+
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5737
|
+
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5740
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5741
|
+
}
|
|
5742
|
+
});
|
|
5743
|
+
return program;
|
|
5744
|
+
}
|
|
5745
|
+
var init_cli = __esm({
|
|
5746
|
+
"src/schema/cli.ts"() {
|
|
5747
|
+
init_goneat_bridge();
|
|
5748
|
+
init_normalizer();
|
|
5749
|
+
init_registry();
|
|
5750
|
+
init_utils();
|
|
5751
|
+
init_validator();
|
|
5752
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
5753
|
+
const program = createCLI();
|
|
5754
|
+
program.parse(process.argv);
|
|
5755
|
+
}
|
|
5756
|
+
}
|
|
5757
|
+
});
|
|
5758
|
+
|
|
5759
|
+
// src/schema/index.ts
|
|
5760
|
+
var init_schema = __esm({
|
|
5761
|
+
"src/schema/index.ts"() {
|
|
5762
|
+
init_cli();
|
|
5763
|
+
init_errors();
|
|
5764
|
+
init_export();
|
|
5765
|
+
init_goneat_bridge();
|
|
5766
|
+
init_normalizer();
|
|
5767
|
+
init_registry();
|
|
5768
|
+
init_utils();
|
|
5769
|
+
init_validator();
|
|
5770
|
+
}
|
|
5771
|
+
});
|
|
5772
|
+
function deepFreeze6(obj) {
|
|
5773
|
+
Object.freeze(obj);
|
|
5774
|
+
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
5775
|
+
const value = obj[prop];
|
|
5776
|
+
if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
|
|
5777
|
+
deepFreeze6(value);
|
|
5778
|
+
}
|
|
5779
|
+
});
|
|
5780
|
+
return obj;
|
|
5781
|
+
}
|
|
5782
|
+
async function registerEmbeddedIdentity(data) {
|
|
5783
|
+
if (isRegistered) {
|
|
5784
|
+
throw AppIdentityError.alreadyRegistered();
|
|
5785
|
+
}
|
|
5786
|
+
let identity;
|
|
5787
|
+
if (typeof data === "string") {
|
|
5788
|
+
let parsed;
|
|
5789
|
+
try {
|
|
5790
|
+
parsed = parse(data);
|
|
5791
|
+
} catch (error) {
|
|
5792
|
+
throw AppIdentityError.embeddedParseFailed(
|
|
5793
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5794
|
+
);
|
|
5795
|
+
}
|
|
5796
|
+
const result = await validateDataBySchemaId(parsed, APP_IDENTITY_SCHEMA_ID);
|
|
5797
|
+
if (!result.valid) {
|
|
5798
|
+
throw AppIdentityError.embeddedValidationFailed(result.diagnostics);
|
|
5799
|
+
}
|
|
5800
|
+
identity = parsed;
|
|
5801
|
+
} else {
|
|
5802
|
+
const result = await validateDataBySchemaId(data, APP_IDENTITY_SCHEMA_ID);
|
|
5803
|
+
if (!result.valid) {
|
|
5804
|
+
throw AppIdentityError.embeddedValidationFailed(result.diagnostics);
|
|
5805
|
+
}
|
|
5806
|
+
identity = data;
|
|
5807
|
+
}
|
|
5808
|
+
embeddedIdentity = deepFreeze6(structuredClone(identity));
|
|
5809
|
+
isRegistered = true;
|
|
5810
|
+
}
|
|
5811
|
+
function hasEmbeddedIdentity() {
|
|
5812
|
+
return isRegistered;
|
|
5813
|
+
}
|
|
5814
|
+
function getEmbeddedIdentity() {
|
|
5815
|
+
return embeddedIdentity;
|
|
5816
|
+
}
|
|
5817
|
+
function clearEmbeddedIdentity() {
|
|
5818
|
+
embeddedIdentity = null;
|
|
5819
|
+
isRegistered = false;
|
|
5820
|
+
}
|
|
5821
|
+
var embeddedIdentity, isRegistered;
|
|
5822
|
+
var init_embedded = __esm({
|
|
5823
|
+
"src/appidentity/embedded.ts"() {
|
|
5824
|
+
init_schema();
|
|
5825
|
+
init_constants();
|
|
5826
|
+
init_errors5();
|
|
5827
|
+
embeddedIdentity = null;
|
|
5828
|
+
isRegistered = false;
|
|
5670
5829
|
}
|
|
5671
5830
|
});
|
|
5672
5831
|
|
|
5673
5832
|
// src/appidentity/index.ts
|
|
5674
5833
|
init_constants();
|
|
5834
|
+
init_embedded();
|
|
5675
5835
|
init_errors5();
|
|
5676
5836
|
|
|
5677
5837
|
// src/appidentity/helpers.ts
|
|
@@ -5716,6 +5876,6 @@ async function getEnvVar(key, options) {
|
|
|
5716
5876
|
// src/appidentity/index.ts
|
|
5717
5877
|
init_loader2();
|
|
5718
5878
|
|
|
5719
|
-
export { APP_IDENTITY_DIR, APP_IDENTITY_ENV_VAR, APP_IDENTITY_FILENAME, APP_IDENTITY_SCHEMA_ID, AppIdentityError, MAX_ANCESTOR_SEARCH_DEPTH, buildEnvVar, clearIdentityCache, getBinaryName, getCachedIdentity, getConfigIdentifiers, getConfigName, getEnvPrefix, getEnvVar, getTelemetryNamespace, getVendor, loadIdentity };
|
|
5879
|
+
export { APP_IDENTITY_DIR, APP_IDENTITY_ENV_VAR, APP_IDENTITY_FILENAME, APP_IDENTITY_SCHEMA_ID, AppIdentityError, MAX_ANCESTOR_SEARCH_DEPTH, buildEnvVar, clearEmbeddedIdentity, clearIdentityCache, getBinaryName, getCachedIdentity, getConfigIdentifiers, getConfigName, getEmbeddedIdentity, getEnvPrefix, getEnvVar, getTelemetryNamespace, getVendor, hasEmbeddedIdentity, loadIdentity, registerEmbeddedIdentity };
|
|
5720
5880
|
//# sourceMappingURL=index.js.map
|
|
5721
5881
|
//# sourceMappingURL=index.js.map
|