monora-ai 2.1.0 → 2.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +339 -158
  2. package/dist/aims_governance.d.ts +238 -0
  3. package/dist/aims_governance.d.ts.map +1 -0
  4. package/dist/aims_governance.js +922 -0
  5. package/dist/alerts.d.ts +16 -0
  6. package/dist/alerts.d.ts.map +1 -1
  7. package/dist/alerts.js +16 -0
  8. package/dist/api.d.ts +6 -0
  9. package/dist/api.d.ts.map +1 -1
  10. package/dist/api.js +6 -0
  11. package/dist/assessment.d.ts +85 -0
  12. package/dist/assessment.d.ts.map +1 -1
  13. package/dist/assessment.js +525 -13
  14. package/dist/attribution.d.ts +44 -3
  15. package/dist/attribution.d.ts.map +1 -1
  16. package/dist/attribution.js +197 -10
  17. package/dist/autodetect.d.ts +68 -0
  18. package/dist/autodetect.d.ts.map +1 -1
  19. package/dist/autodetect.js +639 -0
  20. package/dist/bias.d.ts +130 -0
  21. package/dist/bias.d.ts.map +1 -0
  22. package/dist/bias.js +223 -0
  23. package/dist/cli/diagnostics.d.ts +5 -1
  24. package/dist/cli/diagnostics.d.ts.map +1 -1
  25. package/dist/cli/diagnostics.js +23 -6
  26. package/dist/cli/doctor.d.ts +25 -0
  27. package/dist/cli/doctor.d.ts.map +1 -0
  28. package/dist/cli/doctor.js +381 -0
  29. package/dist/cli/fix.d.ts +16 -0
  30. package/dist/cli/fix.d.ts.map +1 -0
  31. package/dist/cli/fix.js +284 -0
  32. package/dist/cli/init.d.ts +57 -0
  33. package/dist/cli/init.d.ts.map +1 -0
  34. package/dist/cli/init.js +205 -0
  35. package/dist/cli.js +1564 -177
  36. package/dist/complianceConsolidation.d.ts +17 -0
  37. package/dist/complianceConsolidation.d.ts.map +1 -0
  38. package/dist/complianceConsolidation.js +68 -0
  39. package/dist/complianceTargets.d.ts +111 -0
  40. package/dist/complianceTargets.d.ts.map +1 -0
  41. package/dist/complianceTargets.js +521 -0
  42. package/dist/config.d.ts +261 -16
  43. package/dist/config.d.ts.map +1 -1
  44. package/dist/config.js +381 -32
  45. package/dist/config_migrations.d.ts.map +1 -1
  46. package/dist/config_migrations.js +38 -1
  47. package/dist/config_schema.d.ts +2490 -1035
  48. package/dist/config_schema.d.ts.map +1 -1
  49. package/dist/config_schema.js +233 -64
  50. package/dist/context.d.ts +34 -0
  51. package/dist/context.d.ts.map +1 -1
  52. package/dist/context.js +118 -7
  53. package/dist/control_backbone.d.ts +128 -0
  54. package/dist/control_backbone.d.ts.map +1 -0
  55. package/dist/control_backbone.js +826 -0
  56. package/dist/data-governance.d.ts +187 -0
  57. package/dist/data-governance.d.ts.map +1 -0
  58. package/dist/data-governance.js +424 -0
  59. package/dist/dataResidency.d.ts +44 -0
  60. package/dist/dataResidency.d.ts.map +1 -0
  61. package/dist/dataResidency.js +203 -0
  62. package/dist/dispatcher.d.ts.map +1 -1
  63. package/dist/dispatcher.js +17 -5
  64. package/dist/evidence_store.d.ts +103 -0
  65. package/dist/evidence_store.d.ts.map +1 -0
  66. package/dist/evidence_store.js +459 -0
  67. package/dist/executiveSummary.d.ts +15 -0
  68. package/dist/executiveSummary.d.ts.map +1 -1
  69. package/dist/executiveSummary.js +135 -22
  70. package/dist/identity.d.ts +143 -0
  71. package/dist/identity.d.ts.map +1 -0
  72. package/dist/identity.js +231 -0
  73. package/dist/impact-assessment.d.ts +350 -0
  74. package/dist/impact-assessment.d.ts.map +1 -0
  75. package/dist/impact-assessment.js +580 -0
  76. package/dist/index.d.ts +21 -4
  77. package/dist/index.d.ts.map +1 -1
  78. package/dist/index.js +254 -5
  79. package/dist/instrumentation.d.ts +1 -1
  80. package/dist/instrumentation.d.ts.map +1 -1
  81. package/dist/instrumentation.js +123 -22
  82. package/dist/integrations/anthropic.d.ts +3 -0
  83. package/dist/integrations/anthropic.d.ts.map +1 -1
  84. package/dist/integrations/anthropic.js +282 -80
  85. package/dist/integrations/governance.d.ts +33 -0
  86. package/dist/integrations/governance.d.ts.map +1 -0
  87. package/dist/integrations/governance.js +208 -0
  88. package/dist/integrations/langchain.d.ts +4 -0
  89. package/dist/integrations/langchain.d.ts.map +1 -1
  90. package/dist/integrations/langchain.js +362 -142
  91. package/dist/integrations/openai.d.ts +9 -0
  92. package/dist/integrations/openai.d.ts.map +1 -1
  93. package/dist/integrations/openai.js +673 -73
  94. package/dist/iso42001_consolidation.d.ts +16 -0
  95. package/dist/iso42001_consolidation.d.ts.map +1 -0
  96. package/dist/iso42001_consolidation.js +413 -0
  97. package/dist/iso42001_workflows.d.ts +263 -0
  98. package/dist/iso42001_workflows.d.ts.map +1 -0
  99. package/dist/iso42001_workflows.js +781 -0
  100. package/dist/lifecycle.d.ts +299 -0
  101. package/dist/lifecycle.d.ts.map +1 -0
  102. package/dist/lifecycle.js +624 -0
  103. package/dist/lineage.d.ts +2 -2
  104. package/dist/lineage.d.ts.map +1 -1
  105. package/dist/lineage.js +9 -16
  106. package/dist/middleware/express.d.ts.map +1 -1
  107. package/dist/middleware/express.js +18 -3
  108. package/dist/middleware/nextjs.js +2 -2
  109. package/dist/model.d.ts +143 -0
  110. package/dist/model.d.ts.map +1 -0
  111. package/dist/model.js +371 -0
  112. package/dist/onboarding.d.ts +42 -0
  113. package/dist/onboarding.d.ts.map +1 -0
  114. package/dist/onboarding.js +1075 -0
  115. package/dist/oversight.d.ts +264 -0
  116. package/dist/oversight.d.ts.map +1 -0
  117. package/dist/oversight.js +497 -0
  118. package/dist/presets.js +7 -7
  119. package/dist/quotas.d.ts +171 -0
  120. package/dist/quotas.d.ts.map +1 -0
  121. package/dist/quotas.js +259 -0
  122. package/dist/register.d.ts +13 -0
  123. package/dist/register.d.ts.map +1 -0
  124. package/dist/register.js +99 -0
  125. package/dist/registry.d.ts +1 -0
  126. package/dist/registry.d.ts.map +1 -1
  127. package/dist/registry.js +7 -0
  128. package/dist/registryData.json +43 -6
  129. package/dist/report.d.ts +2 -1
  130. package/dist/report.d.ts.map +1 -1
  131. package/dist/report.js +189 -2
  132. package/dist/reporting.d.ts +125 -0
  133. package/dist/reporting.d.ts.map +1 -1
  134. package/dist/reporting.js +192 -2
  135. package/dist/resources.d.ts +285 -0
  136. package/dist/resources.d.ts.map +1 -0
  137. package/dist/resources.js +643 -0
  138. package/dist/risk.d.ts +120 -0
  139. package/dist/risk.d.ts.map +1 -0
  140. package/dist/risk.js +220 -0
  141. package/dist/runtime.d.ts +74 -0
  142. package/dist/runtime.d.ts.map +1 -1
  143. package/dist/runtime.js +416 -18
  144. package/dist/schemaInference.d.ts +92 -0
  145. package/dist/schemaInference.d.ts.map +1 -0
  146. package/dist/schemaInference.js +466 -0
  147. package/dist/schema_validation.js +2 -2
  148. package/dist/schemas/config.schema.json +118 -4
  149. package/dist/security_report.js +4 -4
  150. package/dist/signing.d.ts +1 -1
  151. package/dist/signing.d.ts.map +1 -1
  152. package/dist/signing.js +4 -0
  153. package/dist/sinks/file.d.ts +19 -1
  154. package/dist/sinks/file.d.ts.map +1 -1
  155. package/dist/sinks/file.js +82 -13
  156. package/dist/sinks/https.d.ts +10 -0
  157. package/dist/sinks/https.d.ts.map +1 -1
  158. package/dist/sinks/https.js +76 -16
  159. package/dist/sinks/stdout.d.ts +1 -0
  160. package/dist/sinks/stdout.d.ts.map +1 -1
  161. package/dist/sinks/stdout.js +12 -1
  162. package/dist/spec.d.ts +159 -0
  163. package/dist/spec.d.ts.map +1 -0
  164. package/dist/spec.js +391 -0
  165. package/dist/stakeholders.d.ts +199 -0
  166. package/dist/stakeholders.d.ts.map +1 -0
  167. package/dist/stakeholders.js +398 -0
  168. package/dist/standards.d.ts.map +1 -1
  169. package/dist/standards.js +160 -2
  170. package/dist/standards_ingest.d.ts.map +1 -1
  171. package/dist/standards_ingest.js +1 -4
  172. package/dist/telemetry.d.ts +16 -2
  173. package/dist/telemetry.d.ts.map +1 -1
  174. package/dist/telemetry.js +77 -14
  175. package/dist/templates/controls/gdpr_control_catalog.json +261 -0
  176. package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
  177. package/dist/templates/controls/soc2_control_catalog.json +163 -0
  178. package/dist/templates/standards/iso42001_claims.json +72 -0
  179. package/dist/traced_emitter.d.ts.map +1 -1
  180. package/dist/traced_emitter.js +19 -9
  181. package/dist/trust_package.d.ts +20 -1
  182. package/dist/trust_package.d.ts.map +1 -1
  183. package/dist/trust_package.js +90 -2
  184. package/dist/verify.d.ts.map +1 -1
  185. package/dist/verify.js +9 -2
  186. package/dist/wal.d.ts.map +1 -1
  187. package/dist/wal.js +2 -1
  188. package/package.json +14 -1
  189. package/scripts/postinstall.js +105 -210
  190. package/templates/controls/gdpr_control_catalog.json +261 -0
  191. package/templates/controls/iso42001_control_catalog.json +1443 -0
  192. package/templates/controls/soc2_control_catalog.json +163 -0
  193. package/templates/standards/iso42001_claims.json +72 -0
@@ -0,0 +1,381 @@
1
+ "use strict";
2
+ /**
3
+ * Config doctor checks for Monora CLI.
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.doctorChecks = doctorChecks;
40
+ exports.emitDoctorResults = emitDoctorResults;
41
+ const fs = __importStar(require("fs"));
42
+ const path = __importStar(require("path"));
43
+ const net = __importStar(require("net"));
44
+ const yaml = __importStar(require("js-yaml"));
45
+ const url_1 = require("url");
46
+ const config_1 = require("../config");
47
+ const config_schema_1 = require("../config_schema");
48
+ const REQUIRED_DEPENDENCIES = ['axios', 'js-yaml', 'zod', 'ajv', 'minimatch'];
49
+ async function doctorChecks(configPath, options) {
50
+ const checks = [];
51
+ const errors = [];
52
+ const warnings = [];
53
+ const checkNetwork = options?.checkNetwork ?? true;
54
+ const rawConfigResult = readConfigFile(configPath);
55
+ if (!rawConfigResult.ok) {
56
+ errors.push(rawConfigResult.error || 'Failed to read config');
57
+ checks.push({
58
+ name: 'config_file',
59
+ ok: false,
60
+ level: 'error',
61
+ message: rawConfigResult.error || 'Config file missing or invalid',
62
+ recommendation: 'Create a config with: npx monora-ai init --preset dev',
63
+ });
64
+ }
65
+ else {
66
+ checks.push({
67
+ name: 'config_file',
68
+ ok: true,
69
+ level: 'warning',
70
+ message: `Config file loaded: ${configPath}`,
71
+ });
72
+ }
73
+ for (const dep of REQUIRED_DEPENDENCIES) {
74
+ try {
75
+ require.resolve(dep);
76
+ checks.push({
77
+ name: `dependency:${dep}`,
78
+ ok: true,
79
+ level: 'warning',
80
+ message: `${dep} installed`,
81
+ });
82
+ }
83
+ catch {
84
+ const message = `Missing dependency: ${dep}`;
85
+ errors.push(message);
86
+ checks.push({
87
+ name: `dependency:${dep}`,
88
+ ok: false,
89
+ level: 'error',
90
+ message,
91
+ recommendation: 'Run npm install to restore dependencies',
92
+ });
93
+ }
94
+ }
95
+ if (rawConfigResult.ok && rawConfigResult.config) {
96
+ const nullPaths = findNullPaths(rawConfigResult.config);
97
+ if (nullPaths.length > 0) {
98
+ warnings.push(`Found null values in config: ${nullPaths.join(', ')}`);
99
+ checks.push({
100
+ name: 'null_values',
101
+ ok: false,
102
+ level: 'warning',
103
+ message: `Null values detected at ${nullPaths.join(', ')}`,
104
+ recommendation: 'Run: npx monora-ai config fix --config monora.yml',
105
+ });
106
+ }
107
+ else {
108
+ checks.push({
109
+ name: 'null_values',
110
+ ok: true,
111
+ level: 'warning',
112
+ message: 'No null values detected in config',
113
+ });
114
+ }
115
+ }
116
+ let config = null;
117
+ if (rawConfigResult.ok) {
118
+ try {
119
+ config = (0, config_1.loadConfig)({ configPath });
120
+ }
121
+ catch (error) {
122
+ errors.push(`Failed to load config: ${error?.message || error}`);
123
+ }
124
+ }
125
+ if (config) {
126
+ const env = config.defaults?.environment || 'dev';
127
+ const mode = options?.mode || (env === 'production' ? 'strict' : 'lenient');
128
+ try {
129
+ (0, config_schema_1.validateConfig)(config, { mode });
130
+ checks.push({
131
+ name: 'schema_validation',
132
+ ok: true,
133
+ level: 'warning',
134
+ message: `Schema validation passed (${mode})`,
135
+ });
136
+ }
137
+ catch (error) {
138
+ const message = error instanceof config_schema_1.ConfigValidationError ? error.message : String(error);
139
+ errors.push(message);
140
+ checks.push({
141
+ name: 'schema_validation',
142
+ ok: false,
143
+ level: 'error',
144
+ message: `Schema validation failed (${mode})`,
145
+ recommendation: 'Run: npx monora-ai config fix --config monora.yml',
146
+ });
147
+ }
148
+ const sinkChecks = await checkSinks(config, checkNetwork);
149
+ errors.push(...sinkChecks.errors);
150
+ warnings.push(...sinkChecks.warnings);
151
+ checks.push(...sinkChecks.checks);
152
+ }
153
+ return {
154
+ ok: errors.length === 0,
155
+ errors,
156
+ warnings,
157
+ checks,
158
+ };
159
+ }
160
+ function emitDoctorResults(result, options) {
161
+ const asJson = options?.json ?? false;
162
+ if (asJson) {
163
+ console.log(JSON.stringify(result, null, 2));
164
+ return result.ok ? 0 : 1;
165
+ }
166
+ console.log('\n=== Monora Doctor ===\n');
167
+ for (const check of result.checks) {
168
+ const status = check.ok ? '✓' : '✗';
169
+ const color = check.ok ? '\x1b[32m' : check.level === 'warning' ? '\x1b[33m' : '\x1b[31m';
170
+ const reset = '\x1b[0m';
171
+ console.log(` ${color}${status}${reset} ${check.name}: ${check.message}`);
172
+ if (!check.ok && check.recommendation) {
173
+ console.log(` → ${check.recommendation}`);
174
+ }
175
+ }
176
+ if (result.errors.length > 0) {
177
+ console.log('\nErrors:');
178
+ result.errors.forEach((err) => console.log(` - ${err}`));
179
+ }
180
+ if (result.warnings.length > 0) {
181
+ console.log('\nWarnings:');
182
+ result.warnings.forEach((warn) => console.log(` - ${warn}`));
183
+ }
184
+ if (result.ok) {
185
+ console.log('\n✓ Doctor checks passed.');
186
+ }
187
+ else {
188
+ console.log('\n✗ Doctor checks found issues.');
189
+ }
190
+ return result.ok ? 0 : 1;
191
+ }
192
+ function readConfigFile(configPath) {
193
+ if (!fs.existsSync(configPath)) {
194
+ return { ok: false, error: `Config file not found: ${configPath}` };
195
+ }
196
+ try {
197
+ const raw = fs.readFileSync(configPath, 'utf-8');
198
+ if (configPath.endsWith('.json')) {
199
+ const parsed = raw.trim() ? JSON.parse(raw) : {};
200
+ if (!parsed || typeof parsed !== 'object') {
201
+ return { ok: false, error: 'Config JSON must be an object.' };
202
+ }
203
+ return { ok: true, config: parsed };
204
+ }
205
+ const safeSchema = yaml.SAFE_SCHEMA || yaml.DEFAULT_SCHEMA;
206
+ const parsed = yaml.load(raw, { schema: safeSchema }) || {};
207
+ if (!parsed || typeof parsed !== 'object') {
208
+ return { ok: false, error: 'Config YAML must be a mapping/object.' };
209
+ }
210
+ return { ok: true, config: parsed };
211
+ }
212
+ catch (error) {
213
+ return { ok: false, error: `Invalid config file: ${error?.message || error}` };
214
+ }
215
+ }
216
+ function findNullPaths(value, prefix = []) {
217
+ if (value === null) {
218
+ return [prefix.join('.') || '<root>'];
219
+ }
220
+ if (Array.isArray(value)) {
221
+ return value.flatMap((item, idx) => findNullPaths(item, [...prefix, String(idx)]));
222
+ }
223
+ if (!value || typeof value !== 'object') {
224
+ return [];
225
+ }
226
+ return Object.entries(value).flatMap(([key, item]) => findNullPaths(item, [...prefix, key]));
227
+ }
228
+ async function checkSinks(config, checkNetwork) {
229
+ const errors = [];
230
+ const warnings = [];
231
+ const checks = [];
232
+ const sinks = config.sinks || [];
233
+ if (sinks.length === 0) {
234
+ errors.push('No sinks configured.');
235
+ checks.push({
236
+ name: 'sinks',
237
+ ok: false,
238
+ level: 'error',
239
+ message: 'No sinks configured',
240
+ recommendation: 'Add a file sink or run: npx monora-ai init --preset dev',
241
+ });
242
+ return { errors, warnings, checks };
243
+ }
244
+ for (const [idx, sink] of sinks.entries()) {
245
+ const sinkType = String(sink.type || '').toLowerCase();
246
+ const prefix = `sinks[${idx}]`;
247
+ if (sinkType === 'file') {
248
+ const filePath = String(sink.path || '');
249
+ if (!filePath) {
250
+ errors.push(`${prefix}: file sink requires path`);
251
+ checks.push({
252
+ name: `${prefix}:path`,
253
+ ok: false,
254
+ level: 'error',
255
+ message: 'File sink missing path',
256
+ });
257
+ }
258
+ else {
259
+ const writable = checkFileWritable(filePath);
260
+ if (!writable.ok) {
261
+ const message = `${prefix}: cannot write to ${filePath}`;
262
+ errors.push(message);
263
+ checks.push({
264
+ name: `${prefix}:write`,
265
+ ok: false,
266
+ level: 'error',
267
+ message,
268
+ recommendation: writable.error,
269
+ });
270
+ }
271
+ else {
272
+ checks.push({
273
+ name: `${prefix}:write`,
274
+ ok: true,
275
+ level: 'warning',
276
+ message: `Writable path ${filePath}`,
277
+ });
278
+ }
279
+ }
280
+ continue;
281
+ }
282
+ if (sinkType === 'https' || sinkType === 'http') {
283
+ const endpoint = sink.endpoint;
284
+ if (!endpoint) {
285
+ errors.push(`${prefix}: https sink requires endpoint`);
286
+ checks.push({
287
+ name: `${prefix}:endpoint`,
288
+ ok: false,
289
+ level: 'error',
290
+ message: 'HTTPS sink missing endpoint',
291
+ });
292
+ }
293
+ else if (checkNetwork) {
294
+ const reachable = await checkEndpoint(String(endpoint));
295
+ if (!reachable.ok) {
296
+ warnings.push(`${prefix}: endpoint unreachable: ${reachable.message}`);
297
+ checks.push({
298
+ name: `${prefix}:endpoint`,
299
+ ok: false,
300
+ level: 'warning',
301
+ message: `Endpoint unreachable: ${endpoint}`,
302
+ recommendation: 'Verify endpoint URL or disable HTTPS sink',
303
+ });
304
+ }
305
+ else {
306
+ checks.push({
307
+ name: `${prefix}:endpoint`,
308
+ ok: true,
309
+ level: 'warning',
310
+ message: `Endpoint reachable: ${endpoint}`,
311
+ });
312
+ }
313
+ }
314
+ }
315
+ }
316
+ const webhook = config.alerts?.violation_webhook;
317
+ if (webhook && checkNetwork) {
318
+ const reachable = await checkEndpoint(String(webhook));
319
+ if (!reachable.ok) {
320
+ warnings.push(`alerts.violation_webhook unreachable: ${reachable.message}`);
321
+ checks.push({
322
+ name: 'alerts.webhook',
323
+ ok: false,
324
+ level: 'warning',
325
+ message: `Webhook unreachable: ${webhook}`,
326
+ });
327
+ }
328
+ else {
329
+ checks.push({
330
+ name: 'alerts.webhook',
331
+ ok: true,
332
+ level: 'warning',
333
+ message: `Webhook reachable: ${webhook}`,
334
+ });
335
+ }
336
+ }
337
+ return { errors, warnings, checks };
338
+ }
339
+ function checkFileWritable(filePath) {
340
+ try {
341
+ const dir = path.dirname(filePath) || '.';
342
+ fs.mkdirSync(dir, { recursive: true });
343
+ fs.accessSync(dir, fs.constants.W_OK);
344
+ return { ok: true };
345
+ }
346
+ catch (error) {
347
+ return { ok: false, error: error?.message || String(error) };
348
+ }
349
+ }
350
+ async function checkEndpoint(endpoint) {
351
+ let url;
352
+ try {
353
+ url = new url_1.URL(endpoint);
354
+ }
355
+ catch (error) {
356
+ return { ok: false, message: `invalid URL: ${error?.message || error}` };
357
+ }
358
+ const port = url.port ? Number(url.port) : url.protocol === 'https:' ? 443 : 80;
359
+ const host = url.hostname;
360
+ return new Promise((resolve) => {
361
+ const socket = net.createConnection({ host, port, timeout: 3000 });
362
+ let resolved = false;
363
+ const finalize = (ok, message) => {
364
+ if (resolved)
365
+ return;
366
+ resolved = true;
367
+ resolve({ ok, message });
368
+ };
369
+ socket.on('connect', () => {
370
+ socket.end();
371
+ finalize(true);
372
+ });
373
+ socket.on('error', (err) => {
374
+ finalize(false, err.message);
375
+ });
376
+ socket.on('timeout', () => {
377
+ socket.destroy();
378
+ finalize(false, 'timeout');
379
+ });
380
+ });
381
+ }
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Config auto-fix utilities for Monora CLI.
3
+ */
4
+ export interface FixResult {
5
+ ok: boolean;
6
+ changed: boolean;
7
+ errors: string[];
8
+ warnings: string[];
9
+ changes: string[];
10
+ backupPath?: string;
11
+ }
12
+ export declare function fixConfigFile(configPath: string, options?: {
13
+ dryRun?: boolean;
14
+ checkNetwork?: boolean;
15
+ }): Promise<FixResult>;
16
+ //# sourceMappingURL=fix.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fix.d.ts","sourceRoot":"","sources":["../../src/cli/fix.ts"],"names":[],"mappings":"AAAA;;GAEG;AASH,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,OAAO,CAAC;IACZ,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,wBAAsB,aAAa,CACjC,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAC;IAAC,YAAY,CAAC,EAAE,OAAO,CAAA;CAAE,GACrD,OAAO,CAAC,SAAS,CAAC,CAqDpB"}
@@ -0,0 +1,284 @@
1
+ "use strict";
2
+ /**
3
+ * Config auto-fix utilities for Monora CLI.
4
+ */
5
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
6
+ if (k2 === undefined) k2 = k;
7
+ var desc = Object.getOwnPropertyDescriptor(m, k);
8
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
9
+ desc = { enumerable: true, get: function() { return m[k]; } };
10
+ }
11
+ Object.defineProperty(o, k2, desc);
12
+ }) : (function(o, m, k, k2) {
13
+ if (k2 === undefined) k2 = k;
14
+ o[k2] = m[k];
15
+ }));
16
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
17
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
18
+ }) : function(o, v) {
19
+ o["default"] = v;
20
+ });
21
+ var __importStar = (this && this.__importStar) || (function () {
22
+ var ownKeys = function(o) {
23
+ ownKeys = Object.getOwnPropertyNames || function (o) {
24
+ var ar = [];
25
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
26
+ return ar;
27
+ };
28
+ return ownKeys(o);
29
+ };
30
+ return function (mod) {
31
+ if (mod && mod.__esModule) return mod;
32
+ var result = {};
33
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
34
+ __setModuleDefault(result, mod);
35
+ return result;
36
+ };
37
+ })();
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.fixConfigFile = fixConfigFile;
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
42
+ const net = __importStar(require("net"));
43
+ const yaml = __importStar(require("js-yaml"));
44
+ const url_1 = require("url");
45
+ const config_schema_1 = require("../config_schema");
46
+ async function fixConfigFile(configPath, options) {
47
+ const errors = [];
48
+ const warnings = [];
49
+ const changes = [];
50
+ const checkNetwork = options?.checkNetwork ?? true;
51
+ const readResult = readConfigFile(configPath);
52
+ if (!readResult.ok) {
53
+ errors.push(readResult.error || 'Failed to read config');
54
+ return { ok: false, changed: false, errors, warnings, changes };
55
+ }
56
+ const originalConfig = readResult.config || {};
57
+ let fixedConfig = deepClone(originalConfig);
58
+ const cleaned = (0, config_schema_1.cleanNullValues)(fixedConfig);
59
+ if (JSON.stringify(cleaned) !== JSON.stringify(fixedConfig)) {
60
+ fixedConfig = cleaned;
61
+ changes.push('Removed null values');
62
+ }
63
+ if (fixTelemetryBackend(fixedConfig)) {
64
+ changes.push('Normalized telemetry backend');
65
+ }
66
+ const enumChanges = fixEnumValues(fixedConfig);
67
+ changes.push(...enumChanges);
68
+ const httpsChanges = await removeUnreachableHttpsSinks(fixedConfig, checkNetwork);
69
+ changes.push(...httpsChanges.changes);
70
+ warnings.push(...httpsChanges.warnings);
71
+ if (!fixedConfig.sinks || fixedConfig.sinks.length === 0) {
72
+ fixedConfig.sinks = [{ type: 'file', path: './monora_events.jsonl', rotation: 'none' }];
73
+ changes.push('Added default file sink');
74
+ }
75
+ const changed = changes.length > 0;
76
+ if (!changed) {
77
+ return { ok: true, changed: false, errors, warnings, changes };
78
+ }
79
+ if (options?.dryRun) {
80
+ return { ok: true, changed: true, errors, warnings, changes };
81
+ }
82
+ const backupPath = createBackupPath(configPath);
83
+ fs.copyFileSync(configPath, backupPath);
84
+ const output = renderConfig(fixedConfig, readResult.format);
85
+ fs.writeFileSync(configPath, output, 'utf-8');
86
+ return { ok: true, changed: true, errors, warnings, changes, backupPath };
87
+ }
88
+ function readConfigFile(configPath) {
89
+ if (!fs.existsSync(configPath)) {
90
+ return { ok: false, format: 'yaml', error: `Config file not found: ${configPath}` };
91
+ }
92
+ try {
93
+ const raw = fs.readFileSync(configPath, 'utf-8');
94
+ if (configPath.endsWith('.json')) {
95
+ const parsed = raw.trim() ? JSON.parse(raw) : {};
96
+ if (!parsed || typeof parsed !== 'object') {
97
+ return { ok: false, format: 'json', error: 'Config JSON must be an object.' };
98
+ }
99
+ return { ok: true, config: parsed, format: 'json' };
100
+ }
101
+ const safeSchema = yaml.SAFE_SCHEMA || yaml.DEFAULT_SCHEMA;
102
+ const parsed = yaml.load(raw, { schema: safeSchema }) || {};
103
+ if (!parsed || typeof parsed !== 'object') {
104
+ return { ok: false, format: 'yaml', error: 'Config YAML must be a mapping/object.' };
105
+ }
106
+ return { ok: true, config: parsed, format: 'yaml' };
107
+ }
108
+ catch (error) {
109
+ return { ok: false, format: 'yaml', error: `Invalid config file: ${error?.message || error}` };
110
+ }
111
+ }
112
+ function renderConfig(config, format) {
113
+ if (format === 'json') {
114
+ return JSON.stringify(config, null, 2);
115
+ }
116
+ return yaml.dump(config, { sortKeys: false, noRefs: true });
117
+ }
118
+ function createBackupPath(configPath) {
119
+ const dir = path.dirname(configPath);
120
+ const base = path.basename(configPath);
121
+ const primary = path.join(dir, `${base}.bak`);
122
+ if (!fs.existsSync(primary)) {
123
+ return primary;
124
+ }
125
+ const timestamp = new Date().toISOString().replace(/[:.]/g, '-');
126
+ return path.join(dir, `${base}.bak.${timestamp}`);
127
+ }
128
+ function fixTelemetryBackend(config) {
129
+ if (!config || typeof config !== 'object') {
130
+ return false;
131
+ }
132
+ if (!config.telemetry || typeof config.telemetry !== 'object') {
133
+ return false;
134
+ }
135
+ const backend = config.telemetry.backend;
136
+ if (!backend) {
137
+ return false;
138
+ }
139
+ const valid = new Set(['none', 'minimal', 'memory', 'prometheus', 'statsd']);
140
+ const normalized = String(backend).toLowerCase();
141
+ if (valid.has(normalized)) {
142
+ if (backend !== normalized) {
143
+ config.telemetry.backend = normalized;
144
+ return true;
145
+ }
146
+ return false;
147
+ }
148
+ let replacement = null;
149
+ if (['off', 'false', 'disabled', 'disable', '0', 'none'].includes(normalized)) {
150
+ replacement = 'none';
151
+ }
152
+ else if (normalized.startsWith('prom')) {
153
+ replacement = 'prometheus';
154
+ }
155
+ else if (normalized.startsWith('stat')) {
156
+ replacement = 'statsd';
157
+ }
158
+ else if (normalized.includes('mem')) {
159
+ replacement = 'memory';
160
+ }
161
+ else {
162
+ replacement = config.telemetry.enabled === false ? 'none' : 'minimal';
163
+ }
164
+ if (replacement) {
165
+ config.telemetry.backend = replacement;
166
+ return true;
167
+ }
168
+ return false;
169
+ }
170
+ function fixEnumValues(config) {
171
+ const changes = [];
172
+ if (config?.error_handling && typeof config.error_handling === 'object') {
173
+ const queueMode = String(config.error_handling.queue_full_mode || '');
174
+ if (queueMode && !['warn', 'raise', 'block'].includes(queueMode)) {
175
+ config.error_handling.queue_full_mode = 'warn';
176
+ changes.push('Normalized error_handling.queue_full_mode');
177
+ }
178
+ const sinkMode = String(config.error_handling.sink_failure_mode || '');
179
+ if (sinkMode && !['warn', 'raise', 'silent'].includes(sinkMode)) {
180
+ config.error_handling.sink_failure_mode = 'warn';
181
+ changes.push('Normalized error_handling.sink_failure_mode');
182
+ }
183
+ }
184
+ if (config?.data_handling && typeof config.data_handling === 'object') {
185
+ const mode = String(config.data_handling.mode || '');
186
+ if (mode && !['redact', 'block', 'allow'].includes(mode)) {
187
+ config.data_handling.mode = 'redact';
188
+ changes.push('Normalized data_handling.mode');
189
+ }
190
+ }
191
+ if (Array.isArray(config?.sinks)) {
192
+ for (const sink of config.sinks) {
193
+ if (!sink || typeof sink !== 'object')
194
+ continue;
195
+ if (String(sink.type || '').toLowerCase() === 'file') {
196
+ const rotation = String(sink.rotation || '');
197
+ if (rotation && !['none', 'daily', 'size'].includes(rotation)) {
198
+ sink.rotation = 'none';
199
+ changes.push('Normalized file sink rotation');
200
+ }
201
+ }
202
+ }
203
+ }
204
+ return changes;
205
+ }
206
+ async function removeUnreachableHttpsSinks(config, checkNetwork) {
207
+ const changes = [];
208
+ const warnings = [];
209
+ if (!Array.isArray(config?.sinks)) {
210
+ return { changes, warnings };
211
+ }
212
+ const remaining = [];
213
+ for (const sink of config.sinks) {
214
+ if (!sink || typeof sink !== 'object') {
215
+ remaining.push(sink);
216
+ continue;
217
+ }
218
+ const sinkType = String(sink.type || '').toLowerCase();
219
+ if (sinkType !== 'https' && sinkType !== 'http') {
220
+ remaining.push(sink);
221
+ continue;
222
+ }
223
+ const endpoint = sink.endpoint;
224
+ if (!endpoint || !isValidEndpoint(String(endpoint))) {
225
+ changes.push('Removed HTTPS sink with invalid endpoint');
226
+ continue;
227
+ }
228
+ if (checkNetwork) {
229
+ const reachable = await checkEndpoint(String(endpoint));
230
+ if (!reachable.ok) {
231
+ changes.push('Removed HTTPS sink with unreachable endpoint');
232
+ warnings.push(`HTTPS endpoint unreachable: ${endpoint}`);
233
+ continue;
234
+ }
235
+ }
236
+ remaining.push(sink);
237
+ }
238
+ config.sinks = remaining;
239
+ return { changes, warnings };
240
+ }
241
+ function isValidEndpoint(endpoint) {
242
+ try {
243
+ const url = new url_1.URL(endpoint);
244
+ return url.protocol === 'http:' || url.protocol === 'https:';
245
+ }
246
+ catch {
247
+ return false;
248
+ }
249
+ }
250
+ async function checkEndpoint(endpoint) {
251
+ let url;
252
+ try {
253
+ url = new url_1.URL(endpoint);
254
+ }
255
+ catch (error) {
256
+ return { ok: false, message: `invalid URL: ${error?.message || error}` };
257
+ }
258
+ const port = url.port ? Number(url.port) : url.protocol === 'https:' ? 443 : 80;
259
+ const host = url.hostname;
260
+ return new Promise((resolve) => {
261
+ const socket = net.createConnection({ host, port, timeout: 3000 });
262
+ let resolved = false;
263
+ const finalize = (ok, message) => {
264
+ if (resolved)
265
+ return;
266
+ resolved = true;
267
+ resolve({ ok, message });
268
+ };
269
+ socket.on('connect', () => {
270
+ socket.end();
271
+ finalize(true);
272
+ });
273
+ socket.on('error', (err) => {
274
+ finalize(false, err.message);
275
+ });
276
+ socket.on('timeout', () => {
277
+ socket.destroy();
278
+ finalize(false, 'timeout');
279
+ });
280
+ });
281
+ }
282
+ function deepClone(value) {
283
+ return JSON.parse(JSON.stringify(value));
284
+ }