@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
package/dist/index.js
CHANGED
|
@@ -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, parseDocument } from 'yaml';
|
|
@@ -10,6 +9,7 @@ import addFormats from 'ajv-formats';
|
|
|
10
9
|
import { pipeline, 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
|
import { existsSync, mkdirSync, statSync, createReadStream, createWriteStream, readdirSync, lstatSync } from 'fs';
|
|
15
15
|
import { createGunzip, createGzip } from 'zlib';
|
|
@@ -42,68 +42,6 @@ var init_constants = __esm({
|
|
|
42
42
|
MAX_ANCESTOR_SEARCH_DEPTH = 20;
|
|
43
43
|
}
|
|
44
44
|
});
|
|
45
|
-
var init_correlation = __esm({
|
|
46
|
-
"src/errors/correlation.ts"() {
|
|
47
|
-
}
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
// src/errors/severity.ts
|
|
51
|
-
function getDefaultSeverity() {
|
|
52
|
-
return {
|
|
53
|
-
name: Severity.MEDIUM,
|
|
54
|
-
level: 2
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
var Severity, SEVERITY_LEVELS;
|
|
58
|
-
var init_severity = __esm({
|
|
59
|
-
"src/errors/severity.ts"() {
|
|
60
|
-
Severity = {
|
|
61
|
-
INFO: "info",
|
|
62
|
-
LOW: "low",
|
|
63
|
-
MEDIUM: "medium",
|
|
64
|
-
HIGH: "high",
|
|
65
|
-
CRITICAL: "critical"
|
|
66
|
-
};
|
|
67
|
-
SEVERITY_LEVELS = {
|
|
68
|
-
info: 0,
|
|
69
|
-
low: 1,
|
|
70
|
-
medium: 2,
|
|
71
|
-
high: 3,
|
|
72
|
-
critical: 4
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
// src/errors/serialization.ts
|
|
78
|
-
function extractErrorMessage(error) {
|
|
79
|
-
if (error instanceof Error) {
|
|
80
|
-
return error.message;
|
|
81
|
-
}
|
|
82
|
-
if (isErrorLike(error)) {
|
|
83
|
-
return error.message;
|
|
84
|
-
}
|
|
85
|
-
if (typeof error === "string") {
|
|
86
|
-
return error;
|
|
87
|
-
}
|
|
88
|
-
return String(error);
|
|
89
|
-
}
|
|
90
|
-
function extractStackTrace(error) {
|
|
91
|
-
if (error instanceof Error) {
|
|
92
|
-
return error.stack;
|
|
93
|
-
}
|
|
94
|
-
if (isErrorLike(error) && typeof error.stack === "string") {
|
|
95
|
-
return error.stack;
|
|
96
|
-
}
|
|
97
|
-
return void 0;
|
|
98
|
-
}
|
|
99
|
-
function isErrorLike(value) {
|
|
100
|
-
return typeof value === "object" && value !== null && "message" in value && typeof value.message === "string";
|
|
101
|
-
}
|
|
102
|
-
var init_serialization = __esm({
|
|
103
|
-
"src/errors/serialization.ts"() {
|
|
104
|
-
init_severity();
|
|
105
|
-
}
|
|
106
|
-
});
|
|
107
45
|
|
|
108
46
|
// src/schema/errors.ts
|
|
109
47
|
var errors_exports = {};
|
|
@@ -1594,7 +1532,10 @@ async function loadReferencedSchema(uri) {
|
|
|
1594
1532
|
const repoRoot = join(__dirname4, "..", "..");
|
|
1595
1533
|
let resolvedPath;
|
|
1596
1534
|
if (uri.startsWith("https://schemas.fulmenhq.dev/")) {
|
|
1597
|
-
|
|
1535
|
+
let relativePath = uri.replace("https://schemas.fulmenhq.dev/", "");
|
|
1536
|
+
if (relativePath.startsWith("crucible/")) {
|
|
1537
|
+
relativePath = relativePath.slice("crucible/".length);
|
|
1538
|
+
}
|
|
1598
1539
|
if (relativePath.startsWith("config/taxonomy/")) {
|
|
1599
1540
|
resolvedPath = join(
|
|
1600
1541
|
repoRoot,
|
|
@@ -1811,7 +1752,9 @@ async function compileSchemaById(schemaId, registryOptions) {
|
|
|
1811
1752
|
const aliases = [];
|
|
1812
1753
|
const normalizedRelativePath = metadata.relativePath.replace(/\\/g, "/");
|
|
1813
1754
|
if (normalizedRelativePath) {
|
|
1814
|
-
aliases.push(
|
|
1755
|
+
aliases.push(
|
|
1756
|
+
new URL(`crucible/${normalizedRelativePath}`, "https://schemas.fulmenhq.dev/").toString()
|
|
1757
|
+
);
|
|
1815
1758
|
}
|
|
1816
1759
|
return compileSchema(content, { aliases });
|
|
1817
1760
|
} catch (error) {
|
|
@@ -2329,6 +2272,12 @@ var init_exitCodes = __esm({
|
|
|
2329
2272
|
EXIT_TEST_USAGE_ERROR: 94,
|
|
2330
2273
|
EXIT_TEST_NO_TESTS_COLLECTED: 95,
|
|
2331
2274
|
EXIT_COVERAGE_THRESHOLD_NOT_MET: 96,
|
|
2275
|
+
// Shell & Process Control (124-127)
|
|
2276
|
+
// Exit codes from shell conventions and process control utilities (timeout, exec)
|
|
2277
|
+
EXIT_TIMEOUT: 124,
|
|
2278
|
+
EXIT_TIMEOUT_INTERNAL: 125,
|
|
2279
|
+
EXIT_CANNOT_EXECUTE: 126,
|
|
2280
|
+
EXIT_NOT_FOUND: 127,
|
|
2332
2281
|
// Signal-Induced Exits (128-165)
|
|
2333
2282
|
// 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.
|
|
2334
2283
|
EXIT_SIGNAL_HUP: 129,
|
|
@@ -2666,6 +2615,36 @@ var init_exitCodes = __esm({
|
|
|
2666
2615
|
context: "Code coverage validation, quality gate failure",
|
|
2667
2616
|
category: "testing"
|
|
2668
2617
|
},
|
|
2618
|
+
124: {
|
|
2619
|
+
code: 124,
|
|
2620
|
+
name: "EXIT_TIMEOUT",
|
|
2621
|
+
description: "Command timed out before completion",
|
|
2622
|
+
context: "GNU timeout or similar utility terminated command after deadline",
|
|
2623
|
+
category: "shell"
|
|
2624
|
+
},
|
|
2625
|
+
125: {
|
|
2626
|
+
code: 125,
|
|
2627
|
+
name: "EXIT_TIMEOUT_INTERNAL",
|
|
2628
|
+
description: "Timeout utility itself failed",
|
|
2629
|
+
context: "Error in timeout tool before or during command execution (not command failure)",
|
|
2630
|
+
category: "shell"
|
|
2631
|
+
},
|
|
2632
|
+
126: {
|
|
2633
|
+
code: 126,
|
|
2634
|
+
name: "EXIT_CANNOT_EXECUTE",
|
|
2635
|
+
description: "Command found but could not be executed",
|
|
2636
|
+
context: "Permission denied, not executable, exec format error",
|
|
2637
|
+
category: "shell",
|
|
2638
|
+
bsdEquivalent: "EX_NOPERM (partial)"
|
|
2639
|
+
},
|
|
2640
|
+
127: {
|
|
2641
|
+
code: 127,
|
|
2642
|
+
name: "EXIT_NOT_FOUND",
|
|
2643
|
+
description: "Command not found",
|
|
2644
|
+
context: "Executable not found in PATH or specified path does not exist",
|
|
2645
|
+
category: "shell",
|
|
2646
|
+
bsdEquivalent: "EX_UNAVAILABLE (partial)"
|
|
2647
|
+
},
|
|
2669
2648
|
129: {
|
|
2670
2649
|
code: 129,
|
|
2671
2650
|
name: "EXIT_SIGNAL_HUP",
|
|
@@ -4874,554 +4853,179 @@ var init_cache = __esm({
|
|
|
4874
4853
|
cachedIdentity = null;
|
|
4875
4854
|
}
|
|
4876
4855
|
});
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
const exists = await fileExists(options.path);
|
|
4880
|
-
if (!exists) {
|
|
4881
|
-
throw AppIdentityError.notFound([options.path]);
|
|
4882
|
-
}
|
|
4883
|
-
return { path: options.path, source: "explicit" };
|
|
4884
|
-
}
|
|
4885
|
-
const envPath = process.env[APP_IDENTITY_ENV_VAR];
|
|
4886
|
-
if (envPath) {
|
|
4887
|
-
const exists = await fileExists(envPath);
|
|
4888
|
-
if (!exists) {
|
|
4889
|
-
throw AppIdentityError.envOverrideMissing(envPath);
|
|
4890
|
-
}
|
|
4891
|
-
return { path: envPath, source: "env" };
|
|
4892
|
-
}
|
|
4893
|
-
const startDir = options?.startDir || process.cwd();
|
|
4894
|
-
const result = await searchAncestors(startDir);
|
|
4895
|
-
if (result) {
|
|
4896
|
-
return { path: result, source: "ancestor" };
|
|
4897
|
-
}
|
|
4898
|
-
return null;
|
|
4899
|
-
}
|
|
4900
|
-
async function searchAncestors(startDir) {
|
|
4901
|
-
let currentDir = startDir;
|
|
4902
|
-
const searchedPaths = [];
|
|
4903
|
-
for (let i = 0; i < MAX_ANCESTOR_SEARCH_DEPTH; i++) {
|
|
4904
|
-
const candidatePath = join(currentDir, APP_IDENTITY_DIR, APP_IDENTITY_FILENAME);
|
|
4905
|
-
searchedPaths.push(candidatePath);
|
|
4906
|
-
if (await fileExists(candidatePath)) {
|
|
4907
|
-
return candidatePath;
|
|
4908
|
-
}
|
|
4909
|
-
const parentDir = dirname(currentDir);
|
|
4910
|
-
if (parentDir === currentDir) {
|
|
4911
|
-
throw AppIdentityError.notFound(searchedPaths);
|
|
4912
|
-
}
|
|
4913
|
-
currentDir = parentDir;
|
|
4914
|
-
}
|
|
4915
|
-
throw AppIdentityError.notFound(searchedPaths);
|
|
4916
|
-
}
|
|
4917
|
-
async function fileExists(path) {
|
|
4918
|
-
try {
|
|
4919
|
-
await access(path);
|
|
4920
|
-
return true;
|
|
4921
|
-
} catch {
|
|
4922
|
-
return false;
|
|
4923
|
-
}
|
|
4924
|
-
}
|
|
4925
|
-
var init_discovery = __esm({
|
|
4926
|
-
"src/appidentity/discovery.ts"() {
|
|
4927
|
-
init_constants();
|
|
4928
|
-
init_errors5();
|
|
4856
|
+
var init_correlation = __esm({
|
|
4857
|
+
"src/errors/correlation.ts"() {
|
|
4929
4858
|
}
|
|
4930
4859
|
});
|
|
4931
4860
|
|
|
4932
|
-
// src/
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
|
|
4937
|
-
|
|
4938
|
-
});
|
|
4939
|
-
function deepFreeze5(obj) {
|
|
4940
|
-
Object.freeze(obj);
|
|
4941
|
-
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
4942
|
-
const value = obj[prop];
|
|
4943
|
-
if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
|
|
4944
|
-
deepFreeze5(value);
|
|
4945
|
-
}
|
|
4946
|
-
});
|
|
4947
|
-
return obj;
|
|
4861
|
+
// src/errors/severity.ts
|
|
4862
|
+
function getDefaultSeverity() {
|
|
4863
|
+
return {
|
|
4864
|
+
name: Severity.MEDIUM,
|
|
4865
|
+
level: 2
|
|
4866
|
+
};
|
|
4948
4867
|
}
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4868
|
+
var Severity, SEVERITY_LEVELS;
|
|
4869
|
+
var init_severity = __esm({
|
|
4870
|
+
"src/errors/severity.ts"() {
|
|
4871
|
+
Severity = {
|
|
4872
|
+
INFO: "info",
|
|
4873
|
+
LOW: "low",
|
|
4874
|
+
MEDIUM: "medium",
|
|
4875
|
+
HIGH: "high",
|
|
4876
|
+
CRITICAL: "critical"
|
|
4877
|
+
};
|
|
4878
|
+
SEVERITY_LEVELS = {
|
|
4879
|
+
info: 0,
|
|
4880
|
+
low: 1,
|
|
4881
|
+
medium: 2,
|
|
4882
|
+
high: 3,
|
|
4883
|
+
critical: 4
|
|
4884
|
+
};
|
|
4952
4885
|
}
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4886
|
+
});
|
|
4887
|
+
|
|
4888
|
+
// src/errors/serialization.ts
|
|
4889
|
+
function extractErrorMessage(error) {
|
|
4890
|
+
if (error instanceof Error) {
|
|
4891
|
+
return error.message;
|
|
4958
4892
|
}
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
startDir: options?.startDir
|
|
4962
|
-
});
|
|
4963
|
-
if (!discovery) {
|
|
4964
|
-
throw AppIdentityError.notFound([]);
|
|
4893
|
+
if (isErrorLike(error)) {
|
|
4894
|
+
return error.message;
|
|
4965
4895
|
}
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
content = await readFile(discovery.path, "utf-8");
|
|
4969
|
-
} catch (error) {
|
|
4970
|
-
throw AppIdentityError.readFailed(
|
|
4971
|
-
discovery.path,
|
|
4972
|
-
error instanceof Error ? error : new Error(String(error))
|
|
4973
|
-
);
|
|
4896
|
+
if (typeof error === "string") {
|
|
4897
|
+
return error;
|
|
4974
4898
|
}
|
|
4975
|
-
|
|
4976
|
-
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
|
|
4980
|
-
discovery.path,
|
|
4981
|
-
error instanceof Error ? error : new Error(String(error))
|
|
4982
|
-
);
|
|
4899
|
+
return String(error);
|
|
4900
|
+
}
|
|
4901
|
+
function extractStackTrace(error) {
|
|
4902
|
+
if (error instanceof Error) {
|
|
4903
|
+
return error.stack;
|
|
4983
4904
|
}
|
|
4984
|
-
if (
|
|
4985
|
-
|
|
4986
|
-
if (!result.valid) {
|
|
4987
|
-
throw AppIdentityError.validationFailed(discovery.path, result.diagnostics);
|
|
4988
|
-
}
|
|
4905
|
+
if (isErrorLike(error) && typeof error.stack === "string") {
|
|
4906
|
+
return error.stack;
|
|
4989
4907
|
}
|
|
4990
|
-
|
|
4991
|
-
setCachedIdentity(identity);
|
|
4992
|
-
return identity;
|
|
4908
|
+
return void 0;
|
|
4993
4909
|
}
|
|
4994
|
-
|
|
4995
|
-
"
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
init_errors5();
|
|
4910
|
+
function isErrorLike(value) {
|
|
4911
|
+
return typeof value === "object" && value !== null && "message" in value && typeof value.message === "string";
|
|
4912
|
+
}
|
|
4913
|
+
var init_serialization = __esm({
|
|
4914
|
+
"src/errors/serialization.ts"() {
|
|
4915
|
+
init_severity();
|
|
5001
4916
|
}
|
|
5002
4917
|
});
|
|
5003
|
-
|
|
5004
|
-
|
|
5005
|
-
|
|
5006
|
-
|
|
5007
|
-
|
|
5008
|
-
|
|
5009
|
-
|
|
5010
|
-
|
|
5011
|
-
|
|
5012
|
-
|
|
5013
|
-
|
|
4918
|
+
|
|
4919
|
+
// src/errors/validators.ts
|
|
4920
|
+
async function validateErrorData(data) {
|
|
4921
|
+
return ErrorValidator.getInstance().validate(data);
|
|
4922
|
+
}
|
|
4923
|
+
var ErrorValidator;
|
|
4924
|
+
var init_validators2 = __esm({
|
|
4925
|
+
"src/errors/validators.ts"() {
|
|
4926
|
+
init_schema();
|
|
4927
|
+
ErrorValidator = class _ErrorValidator {
|
|
4928
|
+
static instance;
|
|
4929
|
+
validateFn = null;
|
|
4930
|
+
initPromise = null;
|
|
4931
|
+
initError = null;
|
|
4932
|
+
constructor() {
|
|
5014
4933
|
}
|
|
5015
|
-
|
|
5016
|
-
|
|
5017
|
-
|
|
5018
|
-
|
|
5019
|
-
|
|
5020
|
-
|
|
5021
|
-
if (schema.description) {
|
|
5022
|
-
console.log(` Description: ${schema.description}`);
|
|
4934
|
+
/**
|
|
4935
|
+
* Get singleton instance
|
|
4936
|
+
*/
|
|
4937
|
+
static getInstance() {
|
|
4938
|
+
if (!_ErrorValidator.instance) {
|
|
4939
|
+
_ErrorValidator.instance = new _ErrorValidator();
|
|
5023
4940
|
}
|
|
5024
|
-
|
|
5025
|
-
}
|
|
5026
|
-
} catch (error) {
|
|
5027
|
-
console.error("Error listing schemas:", error.message);
|
|
5028
|
-
process.exit(1);
|
|
5029
|
-
}
|
|
5030
|
-
});
|
|
5031
|
-
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) => {
|
|
5032
|
-
try {
|
|
5033
|
-
const registry = getSchemaRegistry({
|
|
5034
|
-
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5035
|
-
});
|
|
5036
|
-
const schema = await registry.getSchema(cmdOptions.schemaId);
|
|
5037
|
-
console.log("Schema Details:\n");
|
|
5038
|
-
console.log(` ID: ${schema.id}`);
|
|
5039
|
-
console.log(` Format: ${schema.format}`);
|
|
5040
|
-
console.log(` Path: ${schema.path}`);
|
|
5041
|
-
console.log(` Relative Path: ${schema.relativePath}`);
|
|
5042
|
-
if (schema.version) {
|
|
5043
|
-
console.log(` Version: ${schema.version}`);
|
|
5044
|
-
}
|
|
5045
|
-
if (schema.description) {
|
|
5046
|
-
console.log(` Description: ${schema.description}`);
|
|
5047
|
-
}
|
|
5048
|
-
if (schema.schemaDraft) {
|
|
5049
|
-
console.log(` Schema Draft: ${schema.schemaDraft}`);
|
|
4941
|
+
return _ErrorValidator.instance;
|
|
5050
4942
|
}
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
4943
|
+
/**
|
|
4944
|
+
* Initialize validator (lazy load, async)
|
|
4945
|
+
*/
|
|
4946
|
+
async init() {
|
|
4947
|
+
if (this.validateFn !== null || this.initError !== null) {
|
|
4948
|
+
return;
|
|
4949
|
+
}
|
|
4950
|
+
if (this.initPromise) {
|
|
4951
|
+
return this.initPromise;
|
|
4952
|
+
}
|
|
4953
|
+
this.initPromise = (async () => {
|
|
4954
|
+
try {
|
|
4955
|
+
await compileSchemaById("pathfinder/v1.0.0/error-response");
|
|
4956
|
+
await compileSchemaById("assessment/v1.0.0/severity-definitions");
|
|
4957
|
+
this.validateFn = await compileSchemaById("error-handling/v1.0.0/error-response");
|
|
4958
|
+
} catch (err) {
|
|
4959
|
+
this.initError = err instanceof Error ? err : new Error(String(err));
|
|
4960
|
+
throw new Error(`Failed to initialize error validator: ${this.initError.message}`);
|
|
5069
4961
|
}
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
4962
|
+
})();
|
|
4963
|
+
return this.initPromise;
|
|
4964
|
+
}
|
|
4965
|
+
/**
|
|
4966
|
+
* Validate error data against schema
|
|
4967
|
+
*
|
|
4968
|
+
* @param data - Data to validate
|
|
4969
|
+
* @returns Promise resolving to true if valid, false otherwise
|
|
4970
|
+
* @throws {Error} If validator failed to initialize
|
|
4971
|
+
*/
|
|
4972
|
+
async validate(data) {
|
|
4973
|
+
if (this.validateFn === null) {
|
|
4974
|
+
await this.init();
|
|
5081
4975
|
}
|
|
5082
|
-
if (
|
|
5083
|
-
|
|
5084
|
-
process.exit(0);
|
|
5085
|
-
} else {
|
|
5086
|
-
console.log(`\u274C Validation failed (${result.source})`);
|
|
5087
|
-
console.log("\nDiagnostics:");
|
|
5088
|
-
console.log(formatDiagnostics(result.diagnostics));
|
|
5089
|
-
process.exit(1);
|
|
4976
|
+
if (this.initError) {
|
|
4977
|
+
throw this.initError;
|
|
5090
4978
|
}
|
|
5091
|
-
|
|
5092
|
-
|
|
5093
|
-
|
|
4979
|
+
if (!this.validateFn) {
|
|
4980
|
+
throw new Error("Validator not initialized");
|
|
4981
|
+
}
|
|
4982
|
+
return this.validateFn(data);
|
|
5094
4983
|
}
|
|
5095
|
-
|
|
5096
|
-
|
|
5097
|
-
|
|
5098
|
-
|
|
5099
|
-
|
|
5100
|
-
|
|
5101
|
-
|
|
5102
|
-
|
|
5103
|
-
|
|
5104
|
-
|
|
5105
|
-
} else {
|
|
5106
|
-
console.log("\u274C Schema is invalid");
|
|
5107
|
-
console.log("\nDiagnostics:");
|
|
5108
|
-
console.log(formatDiagnostics(result.diagnostics));
|
|
5109
|
-
process.exit(1);
|
|
4984
|
+
/**
|
|
4985
|
+
* Get validation errors from last validation
|
|
4986
|
+
*
|
|
4987
|
+
* @returns Validation errors or null
|
|
4988
|
+
*/
|
|
4989
|
+
getErrors() {
|
|
4990
|
+
if (!this.validateFn) {
|
|
4991
|
+
return null;
|
|
4992
|
+
}
|
|
4993
|
+
return this.validateFn.errors;
|
|
5110
4994
|
}
|
|
5111
|
-
|
|
5112
|
-
|
|
5113
|
-
|
|
5114
|
-
|
|
5115
|
-
|
|
5116
|
-
|
|
5117
|
-
try {
|
|
5118
|
-
const content = await readFile(file, "utf-8");
|
|
5119
|
-
const normalized = normalizeSchema(content, {
|
|
5120
|
-
compact: cmdOptions.compact
|
|
5121
|
-
});
|
|
5122
|
-
if (cmdOptions.output) {
|
|
5123
|
-
await writeFile(cmdOptions.output, normalized, "utf-8");
|
|
5124
|
-
console.log(`\u2705 Normalized schema written to ${cmdOptions.output}`);
|
|
5125
|
-
} else {
|
|
5126
|
-
console.log(normalized);
|
|
4995
|
+
/**
|
|
4996
|
+
* Reset validator state (for testing)
|
|
4997
|
+
* @internal
|
|
4998
|
+
*/
|
|
4999
|
+
static _reset() {
|
|
5000
|
+
_ErrorValidator.instance = new _ErrorValidator();
|
|
5127
5001
|
}
|
|
5128
|
-
}
|
|
5129
|
-
|
|
5130
|
-
|
|
5131
|
-
|
|
5132
|
-
|
|
5133
|
-
|
|
5134
|
-
|
|
5135
|
-
|
|
5136
|
-
|
|
5137
|
-
|
|
5138
|
-
|
|
5139
|
-
|
|
5140
|
-
|
|
5141
|
-
|
|
5002
|
+
};
|
|
5003
|
+
}
|
|
5004
|
+
});
|
|
5005
|
+
|
|
5006
|
+
// src/errors/fulmen-error.ts
|
|
5007
|
+
function isFulmenErrorData(value) {
|
|
5008
|
+
return typeof value === "object" && value !== null && "code" in value && typeof value.code === "string" && "message" in value && typeof value.message === "string";
|
|
5009
|
+
}
|
|
5010
|
+
var FulmenError;
|
|
5011
|
+
var init_fulmen_error = __esm({
|
|
5012
|
+
"src/errors/fulmen-error.ts"() {
|
|
5013
|
+
init_serialization();
|
|
5014
|
+
init_severity();
|
|
5015
|
+
init_validators2();
|
|
5016
|
+
FulmenError = class _FulmenError extends Error {
|
|
5017
|
+
data;
|
|
5018
|
+
constructor(data) {
|
|
5019
|
+
super(data.message);
|
|
5020
|
+
this.name = "FulmenError";
|
|
5021
|
+
this.data = Object.freeze({ ...data });
|
|
5022
|
+
Error.captureStackTrace(this, _FulmenError);
|
|
5142
5023
|
}
|
|
5143
|
-
|
|
5144
|
-
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
}
|
|
5149
|
-
process.exit(result.equal ? 0 : 1);
|
|
5150
|
-
} catch (error) {
|
|
5151
|
-
console.error("Error comparing schemas:", error.message);
|
|
5152
|
-
process.exit(1);
|
|
5153
|
-
}
|
|
5154
|
-
});
|
|
5155
|
-
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(
|
|
5156
|
-
async (cmdOptions) => {
|
|
5157
|
-
try {
|
|
5158
|
-
const { exportSchema: exportSchema2 } = await Promise.resolve().then(() => (init_export(), export_exports));
|
|
5159
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5160
|
-
const result = await exportSchema2({
|
|
5161
|
-
schemaId: cmdOptions.schemaId,
|
|
5162
|
-
outPath: cmdOptions.out,
|
|
5163
|
-
includeProvenance: cmdOptions.provenance ?? true,
|
|
5164
|
-
validate: cmdOptions.validate ?? true,
|
|
5165
|
-
overwrite: cmdOptions.force ?? false,
|
|
5166
|
-
format: cmdOptions.format ?? "auto",
|
|
5167
|
-
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5168
|
-
});
|
|
5169
|
-
console.log("\u2705 Schema exported successfully");
|
|
5170
|
-
console.log(` Schema ID: ${result.schemaId}`);
|
|
5171
|
-
console.log(` Output: ${result.outPath}`);
|
|
5172
|
-
console.log(` Format: ${result.format}`);
|
|
5173
|
-
if (result.provenance) {
|
|
5174
|
-
console.log("\nProvenance:");
|
|
5175
|
-
console.log(` Crucible: ${result.provenance.crucible_version}`);
|
|
5176
|
-
console.log(` Library: ${result.provenance.library_version}`);
|
|
5177
|
-
if (result.provenance.revision) {
|
|
5178
|
-
console.log(` Revision: ${result.provenance.revision}`);
|
|
5179
|
-
}
|
|
5180
|
-
console.log(` Exported: ${result.provenance.exported_at}`);
|
|
5181
|
-
}
|
|
5182
|
-
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5183
|
-
} catch (error) {
|
|
5184
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5185
|
-
const { SchemaExportError: SchemaExportError2, SchemaValidationError: SchemaValidationError2, ExportErrorReason: ExportErrorReason2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
5186
|
-
console.error("\u274C Schema export failed:", error.message);
|
|
5187
|
-
if (error instanceof SchemaExportError2) {
|
|
5188
|
-
if (error.outPath) {
|
|
5189
|
-
console.error(` Output path: ${error.outPath}`);
|
|
5190
|
-
}
|
|
5191
|
-
switch (error.reason) {
|
|
5192
|
-
case ExportErrorReason2.FILE_EXISTS:
|
|
5193
|
-
case ExportErrorReason2.WRITE_FAILED:
|
|
5194
|
-
process.exit(exitCodes2.EXIT_FILE_WRITE_ERROR);
|
|
5195
|
-
break;
|
|
5196
|
-
case ExportErrorReason2.INVALID_FORMAT:
|
|
5197
|
-
process.exit(exitCodes2.EXIT_INVALID_ARGUMENT);
|
|
5198
|
-
break;
|
|
5199
|
-
default:
|
|
5200
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5201
|
-
}
|
|
5202
|
-
}
|
|
5203
|
-
if (error instanceof SchemaValidationError2) {
|
|
5204
|
-
const errorMsg = error.message.toLowerCase();
|
|
5205
|
-
if (errorMsg.includes("not found")) {
|
|
5206
|
-
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5207
|
-
}
|
|
5208
|
-
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5209
|
-
}
|
|
5210
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5211
|
-
}
|
|
5212
|
-
}
|
|
5213
|
-
);
|
|
5214
|
-
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) => {
|
|
5215
|
-
try {
|
|
5216
|
-
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5217
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5218
|
-
const identity = await loadIdentity2({ path: cmdOptions.path });
|
|
5219
|
-
if (cmdOptions.json) {
|
|
5220
|
-
console.log(JSON.stringify(identity, null, 2));
|
|
5221
|
-
} else {
|
|
5222
|
-
console.log("Application Identity:\n");
|
|
5223
|
-
console.log(` Binary Name: ${identity.app.binary_name}`);
|
|
5224
|
-
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5225
|
-
console.log(` Env Prefix: ${identity.app.env_prefix}`);
|
|
5226
|
-
console.log(` Config Name: ${identity.app.config_name}`);
|
|
5227
|
-
console.log(` Description: ${identity.app.description}`);
|
|
5228
|
-
if (identity.metadata) {
|
|
5229
|
-
console.log("\nMetadata:");
|
|
5230
|
-
if (identity.metadata.license) {
|
|
5231
|
-
console.log(` License: ${identity.metadata.license}`);
|
|
5232
|
-
}
|
|
5233
|
-
if (identity.metadata.repository_category) {
|
|
5234
|
-
console.log(` Category: ${identity.metadata.repository_category}`);
|
|
5235
|
-
}
|
|
5236
|
-
if (identity.metadata.telemetry_namespace) {
|
|
5237
|
-
console.log(` Telemetry: ${identity.metadata.telemetry_namespace}`);
|
|
5238
|
-
}
|
|
5239
|
-
if (identity.metadata.project_url) {
|
|
5240
|
-
console.log(` Project URL: ${identity.metadata.project_url}`);
|
|
5241
|
-
}
|
|
5242
|
-
}
|
|
5243
|
-
}
|
|
5244
|
-
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5245
|
-
} catch (error) {
|
|
5246
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5247
|
-
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5248
|
-
console.error("\u274C Failed to load identity:", error.message);
|
|
5249
|
-
if (error instanceof AppIdentityError2) {
|
|
5250
|
-
if (error.message.includes("not found")) {
|
|
5251
|
-
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5252
|
-
}
|
|
5253
|
-
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5254
|
-
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5255
|
-
}
|
|
5256
|
-
}
|
|
5257
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5258
|
-
}
|
|
5259
|
-
});
|
|
5260
|
-
program.command("identity-validate").description("Validate application identity against schema").argument("[file]", "Path to app.yaml (defaults to discovery)").action(async (file) => {
|
|
5261
|
-
try {
|
|
5262
|
-
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5263
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5264
|
-
console.log("Validating application identity...");
|
|
5265
|
-
const identity = await loadIdentity2({ path: file });
|
|
5266
|
-
console.log("\u2705 Identity is valid");
|
|
5267
|
-
console.log(` Binary: ${identity.app.binary_name}`);
|
|
5268
|
-
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5269
|
-
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5270
|
-
} catch (error) {
|
|
5271
|
-
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5272
|
-
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5273
|
-
console.error("\u274C Identity validation failed:", error.message);
|
|
5274
|
-
if (error instanceof AppIdentityError2) {
|
|
5275
|
-
if (error.message.includes("not found")) {
|
|
5276
|
-
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5277
|
-
}
|
|
5278
|
-
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5279
|
-
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5280
|
-
}
|
|
5281
|
-
}
|
|
5282
|
-
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5283
|
-
}
|
|
5284
|
-
});
|
|
5285
|
-
return program;
|
|
5286
|
-
}
|
|
5287
|
-
var init_cli = __esm({
|
|
5288
|
-
"src/schema/cli.ts"() {
|
|
5289
|
-
init_goneat_bridge();
|
|
5290
|
-
init_normalizer();
|
|
5291
|
-
init_registry();
|
|
5292
|
-
init_utils();
|
|
5293
|
-
init_validator();
|
|
5294
|
-
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
5295
|
-
const program = createCLI();
|
|
5296
|
-
program.parse(process.argv);
|
|
5297
|
-
}
|
|
5298
|
-
}
|
|
5299
|
-
});
|
|
5300
|
-
|
|
5301
|
-
// src/schema/index.ts
|
|
5302
|
-
var init_schema = __esm({
|
|
5303
|
-
"src/schema/index.ts"() {
|
|
5304
|
-
init_cli();
|
|
5305
|
-
init_errors();
|
|
5306
|
-
init_export();
|
|
5307
|
-
init_goneat_bridge();
|
|
5308
|
-
init_normalizer();
|
|
5309
|
-
init_registry();
|
|
5310
|
-
init_utils();
|
|
5311
|
-
init_validator();
|
|
5312
|
-
}
|
|
5313
|
-
});
|
|
5314
|
-
|
|
5315
|
-
// src/errors/validators.ts
|
|
5316
|
-
async function validateErrorData(data) {
|
|
5317
|
-
return ErrorValidator.getInstance().validate(data);
|
|
5318
|
-
}
|
|
5319
|
-
var ErrorValidator;
|
|
5320
|
-
var init_validators2 = __esm({
|
|
5321
|
-
"src/errors/validators.ts"() {
|
|
5322
|
-
init_schema();
|
|
5323
|
-
ErrorValidator = class _ErrorValidator {
|
|
5324
|
-
static instance;
|
|
5325
|
-
validateFn = null;
|
|
5326
|
-
initPromise = null;
|
|
5327
|
-
initError = null;
|
|
5328
|
-
constructor() {
|
|
5329
|
-
}
|
|
5330
|
-
/**
|
|
5331
|
-
* Get singleton instance
|
|
5332
|
-
*/
|
|
5333
|
-
static getInstance() {
|
|
5334
|
-
if (!_ErrorValidator.instance) {
|
|
5335
|
-
_ErrorValidator.instance = new _ErrorValidator();
|
|
5336
|
-
}
|
|
5337
|
-
return _ErrorValidator.instance;
|
|
5338
|
-
}
|
|
5339
|
-
/**
|
|
5340
|
-
* Initialize validator (lazy load, async)
|
|
5341
|
-
*/
|
|
5342
|
-
async init() {
|
|
5343
|
-
if (this.validateFn !== null || this.initError !== null) {
|
|
5344
|
-
return;
|
|
5345
|
-
}
|
|
5346
|
-
if (this.initPromise) {
|
|
5347
|
-
return this.initPromise;
|
|
5348
|
-
}
|
|
5349
|
-
this.initPromise = (async () => {
|
|
5350
|
-
try {
|
|
5351
|
-
await compileSchemaById("pathfinder/v1.0.0/error-response");
|
|
5352
|
-
await compileSchemaById("assessment/v1.0.0/severity-definitions");
|
|
5353
|
-
this.validateFn = await compileSchemaById("error-handling/v1.0.0/error-response");
|
|
5354
|
-
} catch (err) {
|
|
5355
|
-
this.initError = err instanceof Error ? err : new Error(String(err));
|
|
5356
|
-
throw new Error(`Failed to initialize error validator: ${this.initError.message}`);
|
|
5357
|
-
}
|
|
5358
|
-
})();
|
|
5359
|
-
return this.initPromise;
|
|
5360
|
-
}
|
|
5361
|
-
/**
|
|
5362
|
-
* Validate error data against schema
|
|
5363
|
-
*
|
|
5364
|
-
* @param data - Data to validate
|
|
5365
|
-
* @returns Promise resolving to true if valid, false otherwise
|
|
5366
|
-
* @throws {Error} If validator failed to initialize
|
|
5367
|
-
*/
|
|
5368
|
-
async validate(data) {
|
|
5369
|
-
if (this.validateFn === null) {
|
|
5370
|
-
await this.init();
|
|
5371
|
-
}
|
|
5372
|
-
if (this.initError) {
|
|
5373
|
-
throw this.initError;
|
|
5374
|
-
}
|
|
5375
|
-
if (!this.validateFn) {
|
|
5376
|
-
throw new Error("Validator not initialized");
|
|
5377
|
-
}
|
|
5378
|
-
return this.validateFn(data);
|
|
5379
|
-
}
|
|
5380
|
-
/**
|
|
5381
|
-
* Get validation errors from last validation
|
|
5382
|
-
*
|
|
5383
|
-
* @returns Validation errors or null
|
|
5384
|
-
*/
|
|
5385
|
-
getErrors() {
|
|
5386
|
-
if (!this.validateFn) {
|
|
5387
|
-
return null;
|
|
5388
|
-
}
|
|
5389
|
-
return this.validateFn.errors;
|
|
5390
|
-
}
|
|
5391
|
-
/**
|
|
5392
|
-
* Reset validator state (for testing)
|
|
5393
|
-
* @internal
|
|
5394
|
-
*/
|
|
5395
|
-
static _reset() {
|
|
5396
|
-
_ErrorValidator.instance = new _ErrorValidator();
|
|
5397
|
-
}
|
|
5398
|
-
};
|
|
5399
|
-
}
|
|
5400
|
-
});
|
|
5401
|
-
|
|
5402
|
-
// src/errors/fulmen-error.ts
|
|
5403
|
-
function isFulmenErrorData(value) {
|
|
5404
|
-
return typeof value === "object" && value !== null && "code" in value && typeof value.code === "string" && "message" in value && typeof value.message === "string";
|
|
5405
|
-
}
|
|
5406
|
-
var FulmenError;
|
|
5407
|
-
var init_fulmen_error = __esm({
|
|
5408
|
-
"src/errors/fulmen-error.ts"() {
|
|
5409
|
-
init_serialization();
|
|
5410
|
-
init_severity();
|
|
5411
|
-
init_validators2();
|
|
5412
|
-
FulmenError = class _FulmenError extends Error {
|
|
5413
|
-
data;
|
|
5414
|
-
constructor(data) {
|
|
5415
|
-
super(data.message);
|
|
5416
|
-
this.name = "FulmenError";
|
|
5417
|
-
this.data = Object.freeze({ ...data });
|
|
5418
|
-
Error.captureStackTrace(this, _FulmenError);
|
|
5419
|
-
}
|
|
5420
|
-
/**
|
|
5421
|
-
* Serialize to JSON (schema-compliant)
|
|
5422
|
-
*/
|
|
5423
|
-
toJSON() {
|
|
5424
|
-
return this.data;
|
|
5024
|
+
/**
|
|
5025
|
+
* Serialize to JSON (schema-compliant)
|
|
5026
|
+
*/
|
|
5027
|
+
toJSON() {
|
|
5028
|
+
return this.data;
|
|
5425
5029
|
}
|
|
5426
5030
|
/**
|
|
5427
5031
|
* Check equality with another FulmenError
|
|
@@ -5675,12 +5279,568 @@ ${cause.message}`;
|
|
|
5675
5279
|
${cause.message}`;
|
|
5676
5280
|
return new _AppIdentityError(message, path, cause);
|
|
5677
5281
|
}
|
|
5678
|
-
|
|
5282
|
+
/**
|
|
5283
|
+
* Create error for embedded identity already registered
|
|
5284
|
+
*
|
|
5285
|
+
* Uses first-wins semantics - once registered, cannot be replaced
|
|
5286
|
+
*/
|
|
5287
|
+
static alreadyRegistered() {
|
|
5288
|
+
const message = "Embedded identity already registered. Registration uses first-wins semantics and cannot be replaced.";
|
|
5289
|
+
return new _AppIdentityError(message);
|
|
5290
|
+
}
|
|
5291
|
+
/**
|
|
5292
|
+
* Create error for embedded identity YAML parsing failure
|
|
5293
|
+
*/
|
|
5294
|
+
static embeddedParseFailed(cause) {
|
|
5295
|
+
const message = `Failed to parse embedded identity YAML: ${cause.message}`;
|
|
5296
|
+
return new _AppIdentityError(message, void 0, cause);
|
|
5297
|
+
}
|
|
5298
|
+
/**
|
|
5299
|
+
* Create error for embedded identity schema validation failure
|
|
5300
|
+
*/
|
|
5301
|
+
static embeddedValidationFailed(diagnostics) {
|
|
5302
|
+
const errorCount = diagnostics.filter((d) => d.severity === "ERROR").length;
|
|
5303
|
+
const warningCount = diagnostics.filter((d) => d.severity === "WARN").length;
|
|
5304
|
+
let message = "Invalid embedded identity\n";
|
|
5305
|
+
message += `Validation errors: ${errorCount} error(s), ${warningCount} warning(s)
|
|
5306
|
+
`;
|
|
5307
|
+
const displayDiagnostics = diagnostics.slice(0, 3);
|
|
5308
|
+
for (const diag of displayDiagnostics) {
|
|
5309
|
+
message += ` - ${diag.message}`;
|
|
5310
|
+
if (diag.pointer) {
|
|
5311
|
+
message += ` at ${diag.pointer}`;
|
|
5312
|
+
}
|
|
5313
|
+
message += "\n";
|
|
5314
|
+
}
|
|
5315
|
+
if (diagnostics.length > 3) {
|
|
5316
|
+
message += ` ... and ${diagnostics.length - 3} more
|
|
5317
|
+
`;
|
|
5318
|
+
}
|
|
5319
|
+
return new _AppIdentityError(message);
|
|
5320
|
+
}
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
});
|
|
5324
|
+
async function discoverIdentityPath(options) {
|
|
5325
|
+
if (options?.path) {
|
|
5326
|
+
const exists = await fileExists(options.path);
|
|
5327
|
+
if (!exists) {
|
|
5328
|
+
throw AppIdentityError.notFound([options.path]);
|
|
5329
|
+
}
|
|
5330
|
+
return { path: options.path, source: "explicit" };
|
|
5331
|
+
}
|
|
5332
|
+
const envPath = process.env[APP_IDENTITY_ENV_VAR];
|
|
5333
|
+
if (envPath) {
|
|
5334
|
+
const exists = await fileExists(envPath);
|
|
5335
|
+
if (!exists) {
|
|
5336
|
+
throw AppIdentityError.envOverrideMissing(envPath);
|
|
5337
|
+
}
|
|
5338
|
+
return { path: envPath, source: "env" };
|
|
5339
|
+
}
|
|
5340
|
+
const startDir = options?.startDir || process.cwd();
|
|
5341
|
+
const result = await searchAncestors(startDir);
|
|
5342
|
+
if (result) {
|
|
5343
|
+
return { path: result, source: "ancestor" };
|
|
5344
|
+
}
|
|
5345
|
+
return null;
|
|
5346
|
+
}
|
|
5347
|
+
async function searchAncestors(startDir) {
|
|
5348
|
+
let currentDir = startDir;
|
|
5349
|
+
const searchedPaths = [];
|
|
5350
|
+
for (let i = 0; i < MAX_ANCESTOR_SEARCH_DEPTH; i++) {
|
|
5351
|
+
const candidatePath = join(currentDir, APP_IDENTITY_DIR, APP_IDENTITY_FILENAME);
|
|
5352
|
+
searchedPaths.push(candidatePath);
|
|
5353
|
+
if (await fileExists(candidatePath)) {
|
|
5354
|
+
return candidatePath;
|
|
5355
|
+
}
|
|
5356
|
+
const parentDir = dirname(currentDir);
|
|
5357
|
+
if (parentDir === currentDir) {
|
|
5358
|
+
throw AppIdentityError.notFound(searchedPaths);
|
|
5359
|
+
}
|
|
5360
|
+
currentDir = parentDir;
|
|
5361
|
+
}
|
|
5362
|
+
throw AppIdentityError.notFound(searchedPaths);
|
|
5363
|
+
}
|
|
5364
|
+
async function fileExists(path) {
|
|
5365
|
+
try {
|
|
5366
|
+
await access(path);
|
|
5367
|
+
return true;
|
|
5368
|
+
} catch {
|
|
5369
|
+
return false;
|
|
5370
|
+
}
|
|
5371
|
+
}
|
|
5372
|
+
var init_discovery = __esm({
|
|
5373
|
+
"src/appidentity/discovery.ts"() {
|
|
5374
|
+
init_constants();
|
|
5375
|
+
init_errors5();
|
|
5376
|
+
}
|
|
5377
|
+
});
|
|
5378
|
+
|
|
5379
|
+
// src/appidentity/loader.ts
|
|
5380
|
+
var loader_exports = {};
|
|
5381
|
+
__export(loader_exports, {
|
|
5382
|
+
clearIdentityCache: () => clearIdentityCache,
|
|
5383
|
+
getCachedIdentity: () => getCachedIdentity,
|
|
5384
|
+
loadIdentity: () => loadIdentity
|
|
5385
|
+
});
|
|
5386
|
+
function deepFreeze5(obj) {
|
|
5387
|
+
Object.freeze(obj);
|
|
5388
|
+
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
5389
|
+
const value = obj[prop];
|
|
5390
|
+
if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
|
|
5391
|
+
deepFreeze5(value);
|
|
5392
|
+
}
|
|
5393
|
+
});
|
|
5394
|
+
return obj;
|
|
5395
|
+
}
|
|
5396
|
+
async function loadIdentity(options) {
|
|
5397
|
+
if (options?.identity) {
|
|
5398
|
+
return deepFreeze5(structuredClone(options.identity));
|
|
5399
|
+
}
|
|
5400
|
+
if (!options?.skipCache) {
|
|
5401
|
+
const cached = getCachedIdentity();
|
|
5402
|
+
if (cached) {
|
|
5403
|
+
return cached;
|
|
5404
|
+
}
|
|
5405
|
+
}
|
|
5406
|
+
let discovery;
|
|
5407
|
+
try {
|
|
5408
|
+
discovery = await discoverIdentityPath({
|
|
5409
|
+
path: options?.path,
|
|
5410
|
+
startDir: options?.startDir
|
|
5411
|
+
});
|
|
5412
|
+
} catch (error) {
|
|
5413
|
+
const hasExplicitPath = Boolean(options?.path);
|
|
5414
|
+
const hasEnvOverride = Boolean(process.env[APP_IDENTITY_ENV_VAR]);
|
|
5415
|
+
if (!hasExplicitPath && !hasEnvOverride && error instanceof AppIdentityError) {
|
|
5416
|
+
const embedded = getEmbeddedIdentity();
|
|
5417
|
+
if (embedded) {
|
|
5418
|
+
setCachedIdentity(embedded);
|
|
5419
|
+
return embedded;
|
|
5420
|
+
}
|
|
5421
|
+
}
|
|
5422
|
+
throw error;
|
|
5423
|
+
}
|
|
5424
|
+
if (!discovery) {
|
|
5425
|
+
const embedded = getEmbeddedIdentity();
|
|
5426
|
+
if (embedded) {
|
|
5427
|
+
setCachedIdentity(embedded);
|
|
5428
|
+
return embedded;
|
|
5429
|
+
}
|
|
5430
|
+
throw AppIdentityError.notFound([]);
|
|
5431
|
+
}
|
|
5432
|
+
let content;
|
|
5433
|
+
try {
|
|
5434
|
+
content = await readFile(discovery.path, "utf-8");
|
|
5435
|
+
} catch (error) {
|
|
5436
|
+
throw AppIdentityError.readFailed(
|
|
5437
|
+
discovery.path,
|
|
5438
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5439
|
+
);
|
|
5440
|
+
}
|
|
5441
|
+
let parsed;
|
|
5442
|
+
try {
|
|
5443
|
+
parsed = parse(content);
|
|
5444
|
+
} catch (error) {
|
|
5445
|
+
throw AppIdentityError.parseFailed(
|
|
5446
|
+
discovery.path,
|
|
5447
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5448
|
+
);
|
|
5449
|
+
}
|
|
5450
|
+
if (!options?.skipValidation) {
|
|
5451
|
+
const result = await validateDataBySchemaId(parsed, APP_IDENTITY_SCHEMA_ID);
|
|
5452
|
+
if (!result.valid) {
|
|
5453
|
+
throw AppIdentityError.validationFailed(discovery.path, result.diagnostics);
|
|
5454
|
+
}
|
|
5455
|
+
}
|
|
5456
|
+
const identity = deepFreeze5(structuredClone(parsed));
|
|
5457
|
+
setCachedIdentity(identity);
|
|
5458
|
+
return identity;
|
|
5459
|
+
}
|
|
5460
|
+
var init_loader2 = __esm({
|
|
5461
|
+
"src/appidentity/loader.ts"() {
|
|
5462
|
+
init_schema();
|
|
5463
|
+
init_cache();
|
|
5464
|
+
init_constants();
|
|
5465
|
+
init_discovery();
|
|
5466
|
+
init_embedded();
|
|
5467
|
+
init_errors5();
|
|
5468
|
+
}
|
|
5469
|
+
});
|
|
5470
|
+
function createCLI(options = {}) {
|
|
5471
|
+
const program = new Command();
|
|
5472
|
+
program.name("tsfulmen-schema").description("Schema validation and discovery CLI for Fulmen (developer tool)").version("0.1.0");
|
|
5473
|
+
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) => {
|
|
5474
|
+
try {
|
|
5475
|
+
const schemas = await listSchemas(prefix, {
|
|
5476
|
+
baseDir: cmdOptions?.baseDir || options.baseDir
|
|
5477
|
+
});
|
|
5478
|
+
if (schemas.length === 0) {
|
|
5479
|
+
console.log("No schemas found");
|
|
5480
|
+
return;
|
|
5481
|
+
}
|
|
5482
|
+
console.log(`Found ${schemas.length} schema(s):
|
|
5483
|
+
`);
|
|
5484
|
+
for (const schema of schemas) {
|
|
5485
|
+
console.log(` ${schema.id}`);
|
|
5486
|
+
console.log(` Format: ${schema.format}`);
|
|
5487
|
+
console.log(` Path: ${schema.relativePath}`);
|
|
5488
|
+
if (schema.description) {
|
|
5489
|
+
console.log(` Description: ${schema.description}`);
|
|
5490
|
+
}
|
|
5491
|
+
console.log();
|
|
5492
|
+
}
|
|
5493
|
+
} catch (error) {
|
|
5494
|
+
console.error("Error listing schemas:", error.message);
|
|
5495
|
+
process.exit(1);
|
|
5496
|
+
}
|
|
5497
|
+
});
|
|
5498
|
+
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) => {
|
|
5499
|
+
try {
|
|
5500
|
+
const registry = getSchemaRegistry({
|
|
5501
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5502
|
+
});
|
|
5503
|
+
const schema = await registry.getSchema(cmdOptions.schemaId);
|
|
5504
|
+
console.log("Schema Details:\n");
|
|
5505
|
+
console.log(` ID: ${schema.id}`);
|
|
5506
|
+
console.log(` Format: ${schema.format}`);
|
|
5507
|
+
console.log(` Path: ${schema.path}`);
|
|
5508
|
+
console.log(` Relative Path: ${schema.relativePath}`);
|
|
5509
|
+
if (schema.version) {
|
|
5510
|
+
console.log(` Version: ${schema.version}`);
|
|
5511
|
+
}
|
|
5512
|
+
if (schema.description) {
|
|
5513
|
+
console.log(` Description: ${schema.description}`);
|
|
5514
|
+
}
|
|
5515
|
+
if (schema.schemaDraft) {
|
|
5516
|
+
console.log(` Schema Draft: ${schema.schemaDraft}`);
|
|
5517
|
+
}
|
|
5518
|
+
const content = await readFile(schema.path, "utf-8");
|
|
5519
|
+
console.log("\nSchema Content:");
|
|
5520
|
+
console.log(content);
|
|
5521
|
+
} catch (error) {
|
|
5522
|
+
console.error("Error showing schema:", error.message);
|
|
5523
|
+
process.exit(1);
|
|
5524
|
+
}
|
|
5525
|
+
});
|
|
5526
|
+
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(
|
|
5527
|
+
async (file, cmdOptions) => {
|
|
5528
|
+
try {
|
|
5529
|
+
let result;
|
|
5530
|
+
if (cmdOptions.useGoneat) {
|
|
5531
|
+
const available = await isGoneatAvailable(cmdOptions.goneatPath);
|
|
5532
|
+
if (!available) {
|
|
5533
|
+
console.error("\u274C goneat not available. Install goneat or remove --use-goneat flag.");
|
|
5534
|
+
console.error(" AJV validation (default) works without external dependencies.");
|
|
5535
|
+
process.exit(1);
|
|
5536
|
+
}
|
|
5537
|
+
const registry = getSchemaRegistry({
|
|
5538
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5539
|
+
});
|
|
5540
|
+
const schema = await registry.getSchema(cmdOptions.schemaId);
|
|
5541
|
+
console.log("Using goneat validation...");
|
|
5542
|
+
result = await runGoneatValidation(schema.path, file, cmdOptions.goneatPath);
|
|
5543
|
+
} else {
|
|
5544
|
+
console.log("Using AJV validation...");
|
|
5545
|
+
result = await validateFileBySchemaId(file, cmdOptions.schemaId, {
|
|
5546
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5547
|
+
});
|
|
5548
|
+
}
|
|
5549
|
+
if (result.valid) {
|
|
5550
|
+
console.log(`\u2705 Validation passed (${result.source})`);
|
|
5551
|
+
process.exit(0);
|
|
5552
|
+
} else {
|
|
5553
|
+
console.log(`\u274C Validation failed (${result.source})`);
|
|
5554
|
+
console.log("\nDiagnostics:");
|
|
5555
|
+
console.log(formatDiagnostics(result.diagnostics));
|
|
5556
|
+
process.exit(1);
|
|
5557
|
+
}
|
|
5558
|
+
} catch (error) {
|
|
5559
|
+
console.error("Error validating file:", error.message);
|
|
5560
|
+
process.exit(1);
|
|
5561
|
+
}
|
|
5562
|
+
}
|
|
5563
|
+
);
|
|
5564
|
+
program.command("validate-schema").description("Validate a schema file itself").argument("<file>", "Schema file to validate").action(async (file) => {
|
|
5565
|
+
try {
|
|
5566
|
+
const content = await readFile(file, "utf-8");
|
|
5567
|
+
const { validateSchema: validateSchema2 } = await Promise.resolve().then(() => (init_validator(), validator_exports));
|
|
5568
|
+
const result = await validateSchema2(content);
|
|
5569
|
+
if (result.valid) {
|
|
5570
|
+
console.log("\u2705 Schema is valid");
|
|
5571
|
+
process.exit(0);
|
|
5572
|
+
} else {
|
|
5573
|
+
console.log("\u274C Schema is invalid");
|
|
5574
|
+
console.log("\nDiagnostics:");
|
|
5575
|
+
console.log(formatDiagnostics(result.diagnostics));
|
|
5576
|
+
process.exit(1);
|
|
5577
|
+
}
|
|
5578
|
+
} catch (error) {
|
|
5579
|
+
console.error("Error validating schema:", error.message);
|
|
5580
|
+
process.exit(1);
|
|
5581
|
+
}
|
|
5582
|
+
});
|
|
5583
|
+
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) => {
|
|
5584
|
+
try {
|
|
5585
|
+
const content = await readFile(file, "utf-8");
|
|
5586
|
+
const normalized = normalizeSchema(content, {
|
|
5587
|
+
compact: cmdOptions.compact
|
|
5588
|
+
});
|
|
5589
|
+
if (cmdOptions.output) {
|
|
5590
|
+
await writeFile(cmdOptions.output, normalized, "utf-8");
|
|
5591
|
+
console.log(`\u2705 Normalized schema written to ${cmdOptions.output}`);
|
|
5592
|
+
} else {
|
|
5593
|
+
console.log(normalized);
|
|
5594
|
+
}
|
|
5595
|
+
} catch (error) {
|
|
5596
|
+
console.error("Error normalizing schema:", error.message);
|
|
5597
|
+
process.exit(1);
|
|
5598
|
+
}
|
|
5599
|
+
});
|
|
5600
|
+
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) => {
|
|
5601
|
+
try {
|
|
5602
|
+
const content1 = await readFile(file1, "utf-8");
|
|
5603
|
+
const content2 = await readFile(file2, "utf-8");
|
|
5604
|
+
const result = compareSchemas(content1, content2);
|
|
5605
|
+
if (result.equal) {
|
|
5606
|
+
console.log("\u2705 Schemas are semantically equal");
|
|
5607
|
+
} else {
|
|
5608
|
+
console.log("\u274C Schemas differ");
|
|
5609
|
+
}
|
|
5610
|
+
if (cmdOptions.showNormalized) {
|
|
5611
|
+
console.log("\nNormalized Schema 1:");
|
|
5612
|
+
console.log(result.normalizedA);
|
|
5613
|
+
console.log("\nNormalized Schema 2:");
|
|
5614
|
+
console.log(result.normalizedB);
|
|
5615
|
+
}
|
|
5616
|
+
process.exit(result.equal ? 0 : 1);
|
|
5617
|
+
} catch (error) {
|
|
5618
|
+
console.error("Error comparing schemas:", error.message);
|
|
5619
|
+
process.exit(1);
|
|
5620
|
+
}
|
|
5621
|
+
});
|
|
5622
|
+
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(
|
|
5623
|
+
async (cmdOptions) => {
|
|
5624
|
+
try {
|
|
5625
|
+
const { exportSchema: exportSchema2 } = await Promise.resolve().then(() => (init_export(), export_exports));
|
|
5626
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5627
|
+
const result = await exportSchema2({
|
|
5628
|
+
schemaId: cmdOptions.schemaId,
|
|
5629
|
+
outPath: cmdOptions.out,
|
|
5630
|
+
includeProvenance: cmdOptions.provenance ?? true,
|
|
5631
|
+
validate: cmdOptions.validate ?? true,
|
|
5632
|
+
overwrite: cmdOptions.force ?? false,
|
|
5633
|
+
format: cmdOptions.format ?? "auto",
|
|
5634
|
+
baseDir: cmdOptions.baseDir || options.baseDir
|
|
5635
|
+
});
|
|
5636
|
+
console.log("\u2705 Schema exported successfully");
|
|
5637
|
+
console.log(` Schema ID: ${result.schemaId}`);
|
|
5638
|
+
console.log(` Output: ${result.outPath}`);
|
|
5639
|
+
console.log(` Format: ${result.format}`);
|
|
5640
|
+
if (result.provenance) {
|
|
5641
|
+
console.log("\nProvenance:");
|
|
5642
|
+
console.log(` Crucible: ${result.provenance.crucible_version}`);
|
|
5643
|
+
console.log(` Library: ${result.provenance.library_version}`);
|
|
5644
|
+
if (result.provenance.revision) {
|
|
5645
|
+
console.log(` Revision: ${result.provenance.revision}`);
|
|
5646
|
+
}
|
|
5647
|
+
console.log(` Exported: ${result.provenance.exported_at}`);
|
|
5648
|
+
}
|
|
5649
|
+
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5650
|
+
} catch (error) {
|
|
5651
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5652
|
+
const { SchemaExportError: SchemaExportError2, SchemaValidationError: SchemaValidationError2, ExportErrorReason: ExportErrorReason2 } = await Promise.resolve().then(() => (init_errors(), errors_exports));
|
|
5653
|
+
console.error("\u274C Schema export failed:", error.message);
|
|
5654
|
+
if (error instanceof SchemaExportError2) {
|
|
5655
|
+
if (error.outPath) {
|
|
5656
|
+
console.error(` Output path: ${error.outPath}`);
|
|
5657
|
+
}
|
|
5658
|
+
switch (error.reason) {
|
|
5659
|
+
case ExportErrorReason2.FILE_EXISTS:
|
|
5660
|
+
case ExportErrorReason2.WRITE_FAILED:
|
|
5661
|
+
process.exit(exitCodes2.EXIT_FILE_WRITE_ERROR);
|
|
5662
|
+
break;
|
|
5663
|
+
case ExportErrorReason2.INVALID_FORMAT:
|
|
5664
|
+
process.exit(exitCodes2.EXIT_INVALID_ARGUMENT);
|
|
5665
|
+
break;
|
|
5666
|
+
default:
|
|
5667
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5668
|
+
}
|
|
5669
|
+
}
|
|
5670
|
+
if (error instanceof SchemaValidationError2) {
|
|
5671
|
+
const errorMsg = error.message.toLowerCase();
|
|
5672
|
+
if (errorMsg.includes("not found")) {
|
|
5673
|
+
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5674
|
+
}
|
|
5675
|
+
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5676
|
+
}
|
|
5677
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5678
|
+
}
|
|
5679
|
+
}
|
|
5680
|
+
);
|
|
5681
|
+
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) => {
|
|
5682
|
+
try {
|
|
5683
|
+
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5684
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5685
|
+
const identity = await loadIdentity2({ path: cmdOptions.path });
|
|
5686
|
+
if (cmdOptions.json) {
|
|
5687
|
+
console.log(JSON.stringify(identity, null, 2));
|
|
5688
|
+
} else {
|
|
5689
|
+
console.log("Application Identity:\n");
|
|
5690
|
+
console.log(` Binary Name: ${identity.app.binary_name}`);
|
|
5691
|
+
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5692
|
+
console.log(` Env Prefix: ${identity.app.env_prefix}`);
|
|
5693
|
+
console.log(` Config Name: ${identity.app.config_name}`);
|
|
5694
|
+
console.log(` Description: ${identity.app.description}`);
|
|
5695
|
+
if (identity.metadata) {
|
|
5696
|
+
console.log("\nMetadata:");
|
|
5697
|
+
if (identity.metadata.license) {
|
|
5698
|
+
console.log(` License: ${identity.metadata.license}`);
|
|
5699
|
+
}
|
|
5700
|
+
if (identity.metadata.repository_category) {
|
|
5701
|
+
console.log(` Category: ${identity.metadata.repository_category}`);
|
|
5702
|
+
}
|
|
5703
|
+
if (identity.metadata.telemetry_namespace) {
|
|
5704
|
+
console.log(` Telemetry: ${identity.metadata.telemetry_namespace}`);
|
|
5705
|
+
}
|
|
5706
|
+
if (identity.metadata.project_url) {
|
|
5707
|
+
console.log(` Project URL: ${identity.metadata.project_url}`);
|
|
5708
|
+
}
|
|
5709
|
+
}
|
|
5710
|
+
}
|
|
5711
|
+
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5712
|
+
} catch (error) {
|
|
5713
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5714
|
+
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5715
|
+
console.error("\u274C Failed to load identity:", error.message);
|
|
5716
|
+
if (error instanceof AppIdentityError2) {
|
|
5717
|
+
if (error.message.includes("not found")) {
|
|
5718
|
+
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5719
|
+
}
|
|
5720
|
+
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5721
|
+
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5722
|
+
}
|
|
5723
|
+
}
|
|
5724
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5725
|
+
}
|
|
5726
|
+
});
|
|
5727
|
+
program.command("identity-validate").description("Validate application identity against schema").argument("[file]", "Path to app.yaml (defaults to discovery)").action(async (file) => {
|
|
5728
|
+
try {
|
|
5729
|
+
const { loadIdentity: loadIdentity2 } = await Promise.resolve().then(() => (init_loader2(), loader_exports));
|
|
5730
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5731
|
+
console.log("Validating application identity...");
|
|
5732
|
+
const identity = await loadIdentity2({ path: file });
|
|
5733
|
+
console.log("\u2705 Identity is valid");
|
|
5734
|
+
console.log(` Binary: ${identity.app.binary_name}`);
|
|
5735
|
+
console.log(` Vendor: ${identity.app.vendor}`);
|
|
5736
|
+
process.exit(exitCodes2.EXIT_SUCCESS);
|
|
5737
|
+
} catch (error) {
|
|
5738
|
+
const { exitCodes: exitCodes2 } = await Promise.resolve().then(() => (init_foundry(), foundry_exports));
|
|
5739
|
+
const { AppIdentityError: AppIdentityError2 } = await Promise.resolve().then(() => (init_errors5(), errors_exports2));
|
|
5740
|
+
console.error("\u274C Identity validation failed:", error.message);
|
|
5741
|
+
if (error instanceof AppIdentityError2) {
|
|
5742
|
+
if (error.message.includes("not found")) {
|
|
5743
|
+
process.exit(exitCodes2.EXIT_FILE_NOT_FOUND);
|
|
5744
|
+
}
|
|
5745
|
+
if (error.message.includes("Invalid") || error.message.includes("validation")) {
|
|
5746
|
+
process.exit(exitCodes2.EXIT_DATA_INVALID);
|
|
5747
|
+
}
|
|
5748
|
+
}
|
|
5749
|
+
process.exit(exitCodes2.EXIT_FAILURE);
|
|
5750
|
+
}
|
|
5751
|
+
});
|
|
5752
|
+
return program;
|
|
5753
|
+
}
|
|
5754
|
+
var init_cli = __esm({
|
|
5755
|
+
"src/schema/cli.ts"() {
|
|
5756
|
+
init_goneat_bridge();
|
|
5757
|
+
init_normalizer();
|
|
5758
|
+
init_registry();
|
|
5759
|
+
init_utils();
|
|
5760
|
+
init_validator();
|
|
5761
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
5762
|
+
const program = createCLI();
|
|
5763
|
+
program.parse(process.argv);
|
|
5764
|
+
}
|
|
5765
|
+
}
|
|
5766
|
+
});
|
|
5767
|
+
|
|
5768
|
+
// src/schema/index.ts
|
|
5769
|
+
var init_schema = __esm({
|
|
5770
|
+
"src/schema/index.ts"() {
|
|
5771
|
+
init_cli();
|
|
5772
|
+
init_errors();
|
|
5773
|
+
init_export();
|
|
5774
|
+
init_goneat_bridge();
|
|
5775
|
+
init_normalizer();
|
|
5776
|
+
init_registry();
|
|
5777
|
+
init_utils();
|
|
5778
|
+
init_validator();
|
|
5779
|
+
}
|
|
5780
|
+
});
|
|
5781
|
+
function deepFreeze6(obj) {
|
|
5782
|
+
Object.freeze(obj);
|
|
5783
|
+
Object.getOwnPropertyNames(obj).forEach((prop) => {
|
|
5784
|
+
const value = obj[prop];
|
|
5785
|
+
if (value !== null && (typeof value === "object" || typeof value === "function") && !Object.isFrozen(value)) {
|
|
5786
|
+
deepFreeze6(value);
|
|
5787
|
+
}
|
|
5788
|
+
});
|
|
5789
|
+
return obj;
|
|
5790
|
+
}
|
|
5791
|
+
async function registerEmbeddedIdentity(data) {
|
|
5792
|
+
if (isRegistered) {
|
|
5793
|
+
throw AppIdentityError.alreadyRegistered();
|
|
5794
|
+
}
|
|
5795
|
+
let identity;
|
|
5796
|
+
if (typeof data === "string") {
|
|
5797
|
+
let parsed;
|
|
5798
|
+
try {
|
|
5799
|
+
parsed = parse(data);
|
|
5800
|
+
} catch (error) {
|
|
5801
|
+
throw AppIdentityError.embeddedParseFailed(
|
|
5802
|
+
error instanceof Error ? error : new Error(String(error))
|
|
5803
|
+
);
|
|
5804
|
+
}
|
|
5805
|
+
const result = await validateDataBySchemaId(parsed, APP_IDENTITY_SCHEMA_ID);
|
|
5806
|
+
if (!result.valid) {
|
|
5807
|
+
throw AppIdentityError.embeddedValidationFailed(result.diagnostics);
|
|
5808
|
+
}
|
|
5809
|
+
identity = parsed;
|
|
5810
|
+
} else {
|
|
5811
|
+
const result = await validateDataBySchemaId(data, APP_IDENTITY_SCHEMA_ID);
|
|
5812
|
+
if (!result.valid) {
|
|
5813
|
+
throw AppIdentityError.embeddedValidationFailed(result.diagnostics);
|
|
5814
|
+
}
|
|
5815
|
+
identity = data;
|
|
5816
|
+
}
|
|
5817
|
+
embeddedIdentity = deepFreeze6(structuredClone(identity));
|
|
5818
|
+
isRegistered = true;
|
|
5819
|
+
}
|
|
5820
|
+
function hasEmbeddedIdentity() {
|
|
5821
|
+
return isRegistered;
|
|
5822
|
+
}
|
|
5823
|
+
function getEmbeddedIdentity() {
|
|
5824
|
+
return embeddedIdentity;
|
|
5825
|
+
}
|
|
5826
|
+
function clearEmbeddedIdentity() {
|
|
5827
|
+
embeddedIdentity = null;
|
|
5828
|
+
isRegistered = false;
|
|
5829
|
+
}
|
|
5830
|
+
var embeddedIdentity, isRegistered;
|
|
5831
|
+
var init_embedded = __esm({
|
|
5832
|
+
"src/appidentity/embedded.ts"() {
|
|
5833
|
+
init_schema();
|
|
5834
|
+
init_constants();
|
|
5835
|
+
init_errors5();
|
|
5836
|
+
embeddedIdentity = null;
|
|
5837
|
+
isRegistered = false;
|
|
5679
5838
|
}
|
|
5680
5839
|
});
|
|
5681
5840
|
|
|
5682
5841
|
// src/appidentity/index.ts
|
|
5683
5842
|
init_constants();
|
|
5843
|
+
init_embedded();
|
|
5684
5844
|
init_errors5();
|
|
5685
5845
|
|
|
5686
5846
|
// src/appidentity/helpers.ts
|
|
@@ -7890,8 +8050,8 @@ async function scanZip(archive, options) {
|
|
|
7890
8050
|
var FULPACK_VERSION = "1.0.0";
|
|
7891
8051
|
|
|
7892
8052
|
// src/index.ts
|
|
7893
|
-
var VERSION2 = "0.
|
|
8053
|
+
var VERSION2 = "0.2.0";
|
|
7894
8054
|
|
|
7895
|
-
export { APP_IDENTITY_DIR, APP_IDENTITY_ENV_VAR, APP_IDENTITY_FILENAME, APP_IDENTITY_SCHEMA_ID, AppIdentityError, ArchiveFormat, DocScribeError, DocScribeParseError, DocScribeUnsupportedFormatError, ERROR_CODES, EntryType, FULPACK_VERSION, FulpackOperationError, MAX_ANCESTOR_SEARCH_DEPTH, Operation, VERSION2 as VERSION, __internal, buildEnvVar, checkDecompressionBomb, clearIdentityCache, create, createFulpackError, detectFormat2 as detectFormat, extract, extractHeaders, extractMetadata, getBinaryName, getCachedIdentity, getConfigIdentifiers, getConfigName, getEnvPrefix, getEnvVar, getTelemetryNamespace, getVendor, hasPathTraversal, info, inspectDocument, isAbsolutePath, loadIdentity, normalizeInput, parseFrontmatter, scan, splitDocuments, stripFrontmatter, validatePath, verify };
|
|
8055
|
+
export { APP_IDENTITY_DIR, APP_IDENTITY_ENV_VAR, APP_IDENTITY_FILENAME, APP_IDENTITY_SCHEMA_ID, AppIdentityError, ArchiveFormat, DocScribeError, DocScribeParseError, DocScribeUnsupportedFormatError, ERROR_CODES, EntryType, FULPACK_VERSION, FulpackOperationError, MAX_ANCESTOR_SEARCH_DEPTH, Operation, VERSION2 as VERSION, __internal, buildEnvVar, checkDecompressionBomb, clearEmbeddedIdentity, clearIdentityCache, create, createFulpackError, detectFormat2 as detectFormat, extract, extractHeaders, extractMetadata, getBinaryName, getCachedIdentity, getConfigIdentifiers, getConfigName, getEmbeddedIdentity, getEnvPrefix, getEnvVar, getTelemetryNamespace, getVendor, hasEmbeddedIdentity, hasPathTraversal, info, inspectDocument, isAbsolutePath, loadIdentity, normalizeInput, parseFrontmatter, registerEmbeddedIdentity, scan, splitDocuments, stripFrontmatter, validatePath, verify };
|
|
7896
8056
|
//# sourceMappingURL=index.js.map
|
|
7897
8057
|
//# sourceMappingURL=index.js.map
|