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
package/dist/cli.js CHANGED
@@ -46,6 +46,7 @@ const readline = __importStar(require("readline"));
46
46
  const yaml = __importStar(require("js-yaml"));
47
47
  const axios_1 = __importDefault(require("axios"));
48
48
  const config_1 = require("./config");
49
+ const init_1 = require("./cli/init");
49
50
  const autodetect_1 = require("./autodetect");
50
51
  const report_1 = require("./report");
51
52
  const ai_act_report_1 = require("./ai_act_report");
@@ -55,29 +56,50 @@ const trust_package_1 = require("./trust_package");
55
56
  const schema_validation_1 = require("./schema_validation");
56
57
  const verify_1 = require("./verify");
57
58
  const signing_1 = require("./signing");
59
+ const aims_governance_1 = require("./aims_governance");
60
+ const control_backbone_1 = require("./control_backbone");
58
61
  const diagnostics_1 = require("./cli/diagnostics");
62
+ const doctor_1 = require("./cli/doctor");
63
+ const fix_1 = require("./cli/fix");
59
64
  const compat_1 = require("./compat");
60
65
  const standards_1 = require("./standards");
61
66
  const standards_ingest_1 = require("./standards_ingest");
67
+ const runtime_1 = require("./runtime");
68
+ const onboarding_1 = require("./onboarding");
69
+ const schemaInference_1 = require("./schemaInference");
70
+ const model_1 = require("./model");
71
+ const spec_1 = require("./spec");
72
+ const complianceTargets_1 = require("./complianceTargets");
62
73
  function usage() {
63
- console.log('Usage:');
64
- console.log(' monora init [--path monora.yml] [--format yaml|json] [--yes] [--force]');
65
- console.log(' monora validate [--config monora.yml] [--json]');
66
- console.log(' monora doctor [--config monora.yml] [--json] [--no-network]');
67
- console.log(' monora report --input <events.jsonl> --output <report.json> [--format json|markdown] [--config monora.yml] [--no-schema] [--no-verify] [--no-signature-verify]');
68
- console.log(' monora usage-report --input <events.jsonl> --output <usage.json> [--format json|markdown] [--no-schema]');
69
- console.log(' monora security-review --input <events.jsonl> --output <security.json> [--config monora.yml] [--no-schema] [--sign gpg --gpg-key <id> --bundle <bundle.json>]');
70
- console.log(' monora trust-package --input <events.jsonl> --trace-id <trace_id> --output <trust.json> [--config monora.yml] [--no-schema] [--no-verify] [--no-signature-verify] [--sign gpg --gpg-key <id>]');
71
- console.log(' monora ai-act-report --input <events.jsonl> --output <report.json> [--format json|markdown] [--config monora.yml] [--no-schema]');
72
- console.log(' monora verify --input <events.jsonl> [--config monora.yml] [--no-schema] [--no-verify] [--no-signature-verify] [--no-sequence] [--pretty]');
73
- console.log(' monora retry-queue [--config monora.yml] [--path ./monora_http_queue] [--json] [--clear]');
74
- console.log(' monora compat-report [--baseline <manifest.json>] [--output <report.json>] [--pretty]');
75
- console.log(' monora standards-wizard [--standard SOC2] [--template <claims.json>] [--output <claims.json>] [--input <events.jsonl>] [--config monora.yml] [--report <report.pdf>] [--yes]');
76
- console.log(' monora standards-ingest --report <report.pdf> [--output <ingest.json>] [--text-out <report.txt>] [--ocr] [--pretty]');
77
- console.log(' monora standards-excerpt --ingest <ingest.json> --claims <claims.json> --excerpts <excerpts.json> [--output <claims.json>] [--pretty]');
78
- console.log(' monora standards-suggest --ingest <ingest.json> --claims <claims.json> [--output <suggestions.json>] [--max-per-claim 2] [--window 160] [--pretty]');
79
- console.log(' monora standards-review --ingest <ingest.json> --claims <claims.json> --output <claims.json> [--max-per-claim 2] [--window 160] [--yes]');
80
- console.log(' monora standards-check --input <events.jsonl> [--config monora.yml] [--report <report.pdf>] [--claims <claims.json>] [--output <report.json>] [--pretty] [--max-calls 25]');
74
+ console.log('Usage: npx monora-ai <command> [options]\n');
75
+ console.log('Commands:');
76
+ console.log(' init [--path monora.yml] [--format yaml|json] [--yes] [--force] [--advanced] [--preset minimal|dev|production]');
77
+ console.log(' start [-- <command>] Zero-code instrumentation');
78
+ console.log(' validate [--config monora.yml] [--json] [--mode strict|lenient|warn-only]');
79
+ console.log(' doctor [--config monora.yml] [--json] [--no-network]');
80
+ console.log(' config fix [--config monora.yml] [--dry-run] [--no-network]');
81
+ console.log(' report --input <events.jsonl> --output <report.json> [--format json|markdown] [--config monora.yml] [--no-schema] [--no-verify] [--no-signature-verify]');
82
+ console.log(' usage-report --input <events.jsonl> --output <usage.json> [--format json|markdown] [--no-schema]');
83
+ console.log(' security-review --input <events.jsonl> --output <security.json> [--config monora.yml] [--no-schema] [--sign gpg --gpg-key <id> --bundle <bundle.json>]');
84
+ console.log(' trust-package --input <events.jsonl> --trace-id <trace_id> --output <trust.json> [--config monora.yml] [--control-standard ISO42001|SOC2|GDPR] [options...]');
85
+ console.log(' aims <subcommand> [--state <aims_state.json>]');
86
+ console.log(' ai-act-report --input <events.jsonl> --output <report.json> [--format json|markdown] [--config monora.yml] [--no-schema]');
87
+ console.log(' verify --input <events.jsonl> [--config monora.yml] [--no-schema] [--no-verify] [--no-signature-verify] [--no-sequence] [--pretty]');
88
+ console.log(' retry-queue [--config monora.yml] [--path ./monora_http_queue] [--json] [--clear]');
89
+ console.log(' compat-report [--baseline <manifest.json>] [--output <report.json>] [--pretty]');
90
+ console.log(' standards-wizard [--standard SOC2] [--template <claims.json>] [--output <claims.json>] [--input <events.jsonl>]');
91
+ console.log(' onboard <init|validate|complete|status> [--config monora.yml] [options]');
92
+ console.log(' schema infer --input <events.jsonl> --output <spec.json> [--model-name <name>] [--model-version <ver>] [--compliance-target <framework>]... [--sample-size <n>] [--no-pii] [--report <inference_report.json>] [--contract <schema_contract.json>]');
93
+ console.log(' model create --input <events.jsonl> --output <model.json> [--model-name <name>] [--model-version <ver>] [--compliance-target <framework>]... [--risk-category minimal|limited|high|unacceptable] [--intended-use <text>] [--owner <id>] [--tag <value>]... [--sample-size <n>] [--no-pii] [--config-out <monora.yml|json>] [--config-format yaml|json] [--contract-out <schema_contract.json>]');
94
+ console.log(' production-check [--config monora.yml] [--json] [--fix]');
95
+ console.log(' detect-env [--json]');
96
+ console.log(' upgrade-preset --from <preset> --to <preset> [--output monora.yml] [--json]');
97
+ console.log('\nExamples:');
98
+ console.log(' npx monora-ai init # Quick setup wizard');
99
+ console.log(' npx monora-ai init --preset minimal # Minimal config preset');
100
+ console.log(' npx monora-ai onboard init # Initialize onboarding contract');
101
+ console.log(' npx monora-ai start -- npm run dev # Zero-code instrumentation');
102
+ console.log(' npx monora-ai doctor # Diagnose config issues');
81
103
  }
82
104
  function parseArgs(argv) {
83
105
  const args = argv.slice(2);
@@ -96,6 +118,21 @@ function getFlagValue(args, flag) {
96
118
  function hasFlag(args, flag) {
97
119
  return args.includes(flag);
98
120
  }
121
+ function getFlagValues(args, flag) {
122
+ const values = [];
123
+ for (let i = 0; i < args.length; i++) {
124
+ if (args[i] !== flag) {
125
+ continue;
126
+ }
127
+ const next = args[i + 1];
128
+ if (!next || next.startsWith('--')) {
129
+ throw new Error(`Missing value for ${flag}`);
130
+ }
131
+ values.push(next);
132
+ i += 1;
133
+ }
134
+ return values;
135
+ }
99
136
  function createInterface() {
100
137
  return readline.createInterface({
101
138
  input: process.stdin,
@@ -130,6 +167,108 @@ function parseList(raw) {
130
167
  .map((item) => item.trim())
131
168
  .filter((item) => item.length > 0);
132
169
  }
170
+ function parseOptionalList(raw) {
171
+ if (!raw) {
172
+ return [];
173
+ }
174
+ return parseList(raw.replace(/;/g, ','));
175
+ }
176
+ function parseJsonObject(raw) {
177
+ if (!raw) {
178
+ return undefined;
179
+ }
180
+ let payload;
181
+ try {
182
+ payload = JSON.parse(raw);
183
+ }
184
+ catch (error) {
185
+ throw new Error(`Invalid metadata JSON: ${error instanceof Error ? error.message : String(error)}`);
186
+ }
187
+ if (!payload || typeof payload !== 'object' || Array.isArray(payload)) {
188
+ throw new Error('Metadata JSON must be an object');
189
+ }
190
+ return payload;
191
+ }
192
+ function normalizeInitPreset(value) {
193
+ if (!value) {
194
+ return undefined;
195
+ }
196
+ const normalized = value.toLowerCase();
197
+ if (normalized === 'development') {
198
+ return 'dev';
199
+ }
200
+ if (normalized === 'dev' || normalized === 'minimal' || normalized === 'production') {
201
+ return normalized;
202
+ }
203
+ throw new Error(`Invalid preset '${value}'. Valid presets: minimal, dev, production`);
204
+ }
205
+ function normalizeValidationMode(value) {
206
+ if (!value) {
207
+ return undefined;
208
+ }
209
+ const normalized = value.toLowerCase();
210
+ if (normalized === 'strict')
211
+ return 'strict';
212
+ if (normalized === 'lenient')
213
+ return 'lenient';
214
+ if (normalized === 'warn-only' || normalized === 'warn' || normalized === 'warn_only') {
215
+ return 'warn-only';
216
+ }
217
+ throw new Error(`Invalid validation mode '${value}'. Valid modes: strict, lenient, warn-only`);
218
+ }
219
+ const ROTATION_COMMENT = [
220
+ '# File sink rotation options:',
221
+ '# - rotation: none (default), daily, size',
222
+ '# - When rotation is enabled, set symlink: true to keep stable paths:',
223
+ '# - <path> (e.g., monora_events.jsonl)',
224
+ '# - <path>.latest (e.g., monora_events.latest.jsonl)',
225
+ '#',
226
+ ].join('\n');
227
+ function renderConfigOutput(config, format) {
228
+ if (format === 'json') {
229
+ return JSON.stringify(config, null, 2);
230
+ }
231
+ const body = yaml.dump(config, { sortKeys: false, noRefs: true });
232
+ return `${ROTATION_COMMENT}\n${body}`;
233
+ }
234
+ async function askSinkSelection(rl, defaults) {
235
+ console.log('? Which sinks do you want to enable? (Use space to select)');
236
+ const markers = {
237
+ file: defaults.includes('file') ? '◉' : '◯',
238
+ stdout: defaults.includes('stdout') ? '◉' : '◯',
239
+ https: defaults.includes('https') ? '◉' : '◯',
240
+ };
241
+ console.log(` ${markers.file} File (monora_events.jsonl)`);
242
+ console.log(` ${markers.stdout} Stdout (pretty to console)`);
243
+ console.log(` ${markers.https} HTTPS (requires endpoint URL)`);
244
+ const raw = await ask(rl, 'Selections (file stdout https)', defaults.join(' '));
245
+ const normalized = raw
246
+ .split(/[\\s,]+/)
247
+ .map((entry) => entry.trim().toLowerCase())
248
+ .filter((entry) => entry.length > 0);
249
+ const selected = new Set();
250
+ const add = (value) => {
251
+ selected.add(value);
252
+ };
253
+ for (const token of normalized) {
254
+ if (token === '1' || token.startsWith('f')) {
255
+ add('file');
256
+ }
257
+ else if (token === '2' || token.startsWith('s')) {
258
+ add('stdout');
259
+ }
260
+ else if (token === '3' || token.startsWith('h')) {
261
+ add('https');
262
+ }
263
+ }
264
+ if (selected.size === 0) {
265
+ defaults.forEach((item) => add(item));
266
+ }
267
+ if (selected.size === 0) {
268
+ add('file');
269
+ }
270
+ return Array.from(selected.values());
271
+ }
133
272
  const ENV_PATTERN = /\$\{([^}]+)\}/g;
134
273
  function isValidEndpoint(endpoint) {
135
274
  try {
@@ -164,6 +303,7 @@ function resolveStandardsTemplatePath(standard) {
164
303
  soc2: 'soc2_claims.json',
165
304
  gdpr: 'gdpr_claims.json',
166
305
  iso27001: 'iso27001_claims.json',
306
+ iso42001: 'iso42001_claims.json',
167
307
  iso: 'iso27001_claims.json',
168
308
  };
169
309
  const filename = filenameMap[normalized];
@@ -220,135 +360,228 @@ async function testHttpEndpoint(endpoint, headers, label) {
220
360
  console.warn(`Warning: test POST to ${label} failed: ${message}`);
221
361
  }
222
362
  }
223
- function buildConfig(answers) {
224
- const config = (0, config_1.loadConfig)({ envPrefix: 'MONORA_WIZARD_' });
225
- config.defaults = {
226
- ...config.defaults,
227
- service_name: answers.service_name,
228
- environment: answers.environment,
229
- };
230
- const sinks = [];
231
- if (answers.stdout_sink) {
232
- sinks.push({ type: 'stdout', format: 'json' });
233
- }
234
- if (answers.file_sink) {
235
- sinks.push({
236
- type: 'file',
237
- path: answers.file_path || './monora_events.jsonl',
238
- rotation: 'daily',
239
- max_size_mb: 100,
240
- batch_size: 100,
241
- flush_interval_sec: 5.0,
242
- });
363
+ /**
364
+ * Streamlined 3-question wizard for quick setup.
365
+ * Uses AI-powered detection for smart defaults.
366
+ */
367
+ async function runStreamlinedWizard(configPath, format, assumeYes) {
368
+ console.log('\n\x1b[36m=== Monora Setup ===\x1b[0m\n');
369
+ console.log('Analyzing your project...\n');
370
+ // Run comprehensive detection
371
+ const detection = (0, autodetect_1.detectFramework)();
372
+ const serviceName = (0, autodetect_1.detectServiceName)() || 'monora-app';
373
+ const env = (0, autodetect_1.detectEnvironment)();
374
+ // Display detection results
375
+ console.log('\x1b[32mDetected:\x1b[0m');
376
+ console.log(` Service: ${serviceName}`);
377
+ if (detection.framework) {
378
+ console.log(` Framework: ${detection.framework}`);
379
+ }
380
+ console.log(` Environment: ${env}`);
381
+ if (detection.aiSdks.length > 0) {
382
+ console.log(` AI SDKs: ${detection.aiSdks.map(s => s.name).join(', ')}`);
383
+ }
384
+ if (detection.cloudPlatform) {
385
+ console.log(` Platform: ${detection.cloudPlatform}`);
386
+ }
387
+ if (detection.typescript) {
388
+ console.log(` TypeScript: yes`);
243
389
  }
244
- if (answers.https_sink && answers.https_endpoint) {
245
- const headers = {};
246
- if (answers.https_auth_header) {
247
- headers.Authorization = answers.https_auth_header;
390
+ console.log('');
391
+ // Run AI analysis if API key available
392
+ let aiAnalysis = null;
393
+ const hasAIKey = process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY;
394
+ const aiAnalysisEnabled = ['true', '1', 'yes'].includes(String(process.env.MONORA_AI_ANALYSIS_ENABLED || '').toLowerCase());
395
+ if (hasAIKey && aiAnalysisEnabled) {
396
+ console.log('Running AI-powered analysis...');
397
+ aiAnalysis = await (0, autodetect_1.analyzeProjectWithAI)();
398
+ if (aiAnalysis) {
399
+ console.log(`\x1b[33mAI suggests:\x1b[0m ${aiAnalysis.reasoning}`);
400
+ if (aiAnalysis.complianceHints.length > 0) {
401
+ console.log(` Compliance: ${aiAnalysis.complianceHints.join(', ')}`);
402
+ }
248
403
  }
249
- sinks.push({
250
- type: 'https',
251
- endpoint: answers.https_endpoint,
252
- headers,
253
- batch_size: 50,
254
- timeout_sec: 10.0,
255
- retry_attempts: 3,
256
- backoff_base_sec: 0.5,
257
- });
404
+ console.log('');
258
405
  }
259
- config.sinks = sinks.length > 0 ? sinks : [{ type: 'stdout', format: 'json' }];
260
- config.policies = {
261
- ...config.policies,
262
- model_allowlist: answers.allowlist || [],
263
- model_denylist: answers.denylist || [],
264
- enforce: true,
265
- };
266
- config.instrumentation = {
267
- ...config.instrumentation,
268
- enabled: answers.enable_instrumentation,
269
- default_purpose: answers.instrumentation_purpose,
270
- };
271
- config.data_handling = {
272
- ...config.data_handling,
273
- enabled: answers.enable_data_handling,
274
- mode: (answers.data_handling_mode || 'redact'),
275
- rules: answers.enable_data_handling
276
- ? [
277
- {
278
- name: 'email',
279
- pattern: '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}',
280
- replace: '[REDACTED_EMAIL]',
281
- classifications: ['confidential', 'secret'],
282
- apply_to: ['request', 'response'],
283
- },
284
- ]
285
- : [],
286
- };
287
- config.alerts = {
288
- ...config.alerts,
289
- violation_webhook: answers.violation_webhook || undefined,
290
- headers: answers.alerts_auth_header ? { Authorization: answers.alerts_auth_header } : {},
291
- };
292
- config.error_handling = {
293
- ...config.error_handling,
294
- queue_full_mode: answers.queue_full_mode,
295
- };
296
- config.buffering = {
297
- ...config.buffering,
298
- queue_full_timeout_sec: answers.queue_full_timeout_sec === undefined ? config.buffering?.queue_full_timeout_sec : answers.queue_full_timeout_sec,
299
- };
300
- config.attribution = {
301
- ...config.attribution,
302
- enabled: Boolean(answers.enable_attribution),
303
- };
304
- const project = {
305
- company: answers.attribution_company || undefined,
306
- role: answers.attribution_role || undefined,
307
- email: answers.attribution_email || undefined,
308
- source: answers.attribution_source || undefined,
309
- use_case: answers.attribution_use_case || undefined,
310
- team_size: answers.attribution_team_size || undefined,
311
- business_owner: answers.attribution_business_owner || undefined,
312
- data_categories: answers.attribution_data_categories || [],
313
- };
314
- const hasProject = Object.values(project).some((value) => {
315
- if (value === undefined || value === null)
316
- return false;
317
- if (Array.isArray(value))
318
- return value.length > 0;
319
- return String(value).trim().length > 0;
320
- });
321
- if (hasProject) {
322
- config.attribution.project = project;
323
- }
324
- if (answers.telemetry_enabled || answers.telemetry_send_data) {
325
- config.attribution.telemetry = {
326
- enabled: Boolean(answers.telemetry_enabled),
327
- send_data: Boolean(answers.telemetry_send_data),
328
- data_residency: answers.telemetry_data_residency || undefined,
329
- };
406
+ else if (hasAIKey && !aiAnalysisEnabled) {
407
+ console.log('AI analysis is disabled. Set MONORA_AI_ANALYSIS_ENABLED=true to enable it.\n');
330
408
  }
331
- if (answers.enable_audit_metadata) {
332
- config.audit = {
333
- use_case_name: answers.audit_use_case_name || undefined,
334
- business_owner: answers.audit_business_owner || undefined,
335
- data_categories: answers.audit_data_categories || [],
336
- risk_level: answers.audit_risk_level || 'medium',
337
- compliance_frameworks: answers.audit_compliance_frameworks || [],
338
- review_date: answers.audit_review_date || undefined,
339
- reviewer: answers.audit_reviewer || undefined,
340
- notes: answers.audit_notes || undefined,
341
- };
409
+ // Collect 3 required questions
410
+ let email = '';
411
+ let company = '';
412
+ let role = '';
413
+ if (assumeYes) {
414
+ // Use environment variables or empty
415
+ email = process.env.MONORA_EMAIL || '';
416
+ company = process.env.MONORA_COMPANY || '';
417
+ role = process.env.MONORA_ROLE || '';
418
+ console.log('Using environment variables for attribution...');
419
+ }
420
+ else {
421
+ const rl = createInterface();
422
+ try {
423
+ console.log('\x1b[36mQuick setup (3 questions):\x1b[0m');
424
+ email = (await ask(rl, ' Work email (for updates)', '')).trim();
425
+ company = (await ask(rl, ' Company name', '')).trim();
426
+ role = (await ask(rl, ' Your role', '')).trim();
427
+ }
428
+ finally {
429
+ rl.close();
430
+ }
342
431
  }
343
- return config;
432
+ console.log('');
433
+ // Build smart configuration
434
+ const config = (0, autodetect_1.buildSmartConfig)(detection, aiAnalysis, { email, company, role });
435
+ // Write configuration
436
+ const output = renderConfigOutput(config, format);
437
+ fs.writeFileSync(configPath, output, 'utf-8');
438
+ console.log(`\x1b[32mConfiguration saved to ${configPath}\x1b[0m\n`);
439
+ // Clear next steps
440
+ console.log('\x1b[36m=== Next Steps ===\x1b[0m\n');
441
+ console.log('To start tracing with zero code changes:');
442
+ console.log('\x1b[33m npx monora-ai start\x1b[0m\n');
443
+ console.log('Or wrap your existing command:');
444
+ console.log('\x1b[33m npx monora-ai start -- npm run dev\x1b[0m\n');
445
+ console.log('Or add to package.json scripts:');
446
+ console.log(' "scripts": {');
447
+ console.log(' "dev": "npx monora-ai start -- node server.js"');
448
+ console.log(' }\n');
449
+ if (detection.aiSdks.length > 0) {
450
+ console.log(`Auto-instrumentation enabled for: ${detection.aiSdks.map(s => s.name).join(', ')}`);
451
+ }
452
+ console.log('\nFor advanced configuration, run: \x1b[33mnpx monora-ai init --advanced\x1b[0m');
344
453
  }
345
- async function runInitWizard(configPath, format, assumeYes, force) {
454
+ /**
455
+ * Run a command with Monora instrumentation enabled.
456
+ * Zero-code instrumentation using NODE_OPTIONS.
457
+ */
458
+ async function runStart(args) {
459
+ const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
460
+ // Find the separator '--' for the user command
461
+ const separatorIndex = args.indexOf('--');
462
+ let userCommand;
463
+ if (separatorIndex >= 0) {
464
+ userCommand = args.slice(separatorIndex + 1);
465
+ }
466
+ else if (args.length > 0) {
467
+ userCommand = args;
468
+ }
469
+ else {
470
+ // No command provided - try to find package.json start script
471
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
472
+ if (fs.existsSync(packageJsonPath)) {
473
+ try {
474
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
475
+ if (pkg.scripts?.start) {
476
+ console.log('\x1b[36mNo command specified, running npm start...\x1b[0m\n');
477
+ userCommand = ['npm', 'start'];
478
+ }
479
+ else if (pkg.scripts?.dev) {
480
+ console.log('\x1b[36mNo command specified, running npm run dev...\x1b[0m\n');
481
+ userCommand = ['npm', 'run', 'dev'];
482
+ }
483
+ else {
484
+ console.error('Error: No command specified and no start/dev script found in package.json');
485
+ console.log('\nUsage: npx monora-ai start -- <command>');
486
+ console.log(' npx monora-ai start -- npm run dev');
487
+ console.log(' npx monora-ai start -- node server.js');
488
+ process.exit(1);
489
+ }
490
+ }
491
+ catch {
492
+ console.error('Error: No command specified');
493
+ process.exit(1);
494
+ }
495
+ }
496
+ else {
497
+ console.error('Error: No command specified');
498
+ console.log('\nUsage: npx monora-ai start -- <command>');
499
+ process.exit(1);
500
+ }
501
+ }
502
+ // Find the register module path
503
+ let registerPath;
504
+ try {
505
+ // Try to find monora-ai/register
506
+ registerPath = require.resolve('monora-ai/register');
507
+ }
508
+ catch {
509
+ // Fall back to local path for development
510
+ registerPath = path.resolve(__dirname, 'register.js');
511
+ if (!fs.existsSync(registerPath)) {
512
+ // Try TypeScript version
513
+ registerPath = path.resolve(__dirname, 'register.ts');
514
+ }
515
+ }
516
+ // Check for config file
517
+ const configPath = fs.existsSync('monora.yml')
518
+ ? 'monora.yml'
519
+ : fs.existsSync('monora.json')
520
+ ? 'monora.json'
521
+ : null;
522
+ // Build environment
523
+ const env = {
524
+ ...process.env,
525
+ MONORA_AUTO_INIT: 'true',
526
+ };
527
+ if (configPath) {
528
+ env.MONORA_CONFIG_PATH = configPath;
529
+ }
530
+ // Add register to NODE_OPTIONS
531
+ const existingNodeOptions = process.env.NODE_OPTIONS || '';
532
+ const escapedRegisterPath = registerPath.replace(/"/g, '\\"');
533
+ env.NODE_OPTIONS = `${existingNodeOptions} --require "${escapedRegisterPath}"`.trim();
534
+ console.log('\x1b[36m=== Monora Start ===\x1b[0m\n');
535
+ console.log('Instrumentation: \x1b[32menabled\x1b[0m');
536
+ if (configPath) {
537
+ console.log(`Config: ${configPath}`);
538
+ }
539
+ else {
540
+ console.log('Config: auto-detected');
541
+ }
542
+ console.log(`Running: ${userCommand.join(' ')}\n`);
543
+ console.log('\x1b[90m--- Application Output ---\x1b[0m\n');
544
+ // Spawn the user command
545
+ const child = spawn(userCommand[0], userCommand.slice(1), {
546
+ env,
547
+ stdio: 'inherit',
548
+ shell: true,
549
+ });
550
+ child.on('exit', (code) => {
551
+ process.exit(code ?? 0);
552
+ });
553
+ child.on('error', (err) => {
554
+ console.error(`Failed to start command: ${err.message}`);
555
+ process.exit(1);
556
+ });
557
+ }
558
+ async function runInitWizard(configPath, format, assumeYes, force, advanced = false, preset) {
346
559
  if (fs.existsSync(configPath) && !force) {
347
560
  if (assumeYes) {
348
561
  console.error(`${configPath} already exists. Use --force to overwrite.`);
349
562
  process.exit(1);
350
563
  }
351
564
  }
565
+ if (preset) {
566
+ const detectedService = (0, autodetect_1.detectServiceName)() || path.basename(process.cwd()) || 'monora-app';
567
+ const config = (0, init_1.buildPresetConfig)(preset, { serviceName: detectedService });
568
+ const output = renderConfigOutput(config, format);
569
+ fs.writeFileSync(configPath, output, 'utf-8');
570
+ console.log(`\nMonora config written to ${configPath}`);
571
+ console.log(`Preset: ${preset}`);
572
+ console.log('\n=== Next Steps ===\n');
573
+ console.log('Use the generated config file:');
574
+ console.log(` import { init } from 'monora-ai';`);
575
+ console.log(` init({ configPath: '${configPath}' });`);
576
+ console.log('');
577
+ console.log('Generate reports with:');
578
+ console.log(' npx monora-ai report --input ./monora_events.jsonl --output monora_report.json');
579
+ return;
580
+ }
581
+ // Use streamlined wizard by default (unless --advanced)
582
+ if (!advanced) {
583
+ return runStreamlinedWizard(configPath, format, assumeYes);
584
+ }
352
585
  // Auto-detect project info
353
586
  const detectedService = (0, autodetect_1.detectServiceName)() || path.basename(process.cwd()) || 'monora-app';
354
587
  const detectedEnv = (0, autodetect_1.detectEnvironment)();
@@ -366,26 +599,22 @@ async function runInitWizard(configPath, format, assumeYes, force) {
366
599
  }
367
600
  console.log('');
368
601
  // Generate smart defaults based on detection
369
- const smartAllowlist = detectedSdks.includes('openai') && detectedSdks.includes('anthropic')
370
- ? ['gpt-4*', 'gpt-4o*', 'claude-3-*']
371
- : detectedSdks.includes('openai')
372
- ? ['gpt-4*', 'gpt-4o*', 'o1-*']
373
- : detectedSdks.includes('anthropic')
374
- ? ['claude-3-*', 'claude-sonnet-4-*', 'claude-opus-4-*']
375
- : [];
602
+ const smartAllowlist = [...init_1.DEFAULT_ALLOWLIST_PATTERNS];
376
603
  let answers;
377
604
  if (assumeYes) {
378
605
  // Smart defaults for --yes mode
379
606
  answers = {
380
607
  service_name: detectedService,
381
608
  environment: detectedEnv,
382
- stdout_sink: detectedEnv === 'dev' || detectedEnv === 'poc',
609
+ stdout_sink: false,
610
+ stdout_format: 'pretty',
383
611
  file_sink: true,
384
612
  file_path: detectedEnv === 'production'
385
613
  ? './logs/monora_events.jsonl'
386
614
  : detectedEnv === 'poc'
387
615
  ? './monora_poc_events.jsonl'
388
616
  : './monora_events.jsonl',
617
+ file_rotation: 'none',
389
618
  https_sink: false,
390
619
  enable_policies: smartAllowlist.length > 0,
391
620
  allowlist: smartAllowlist,
@@ -394,30 +623,30 @@ async function runInitWizard(configPath, format, assumeYes, force) {
394
623
  instrumentation_purpose: 'general',
395
624
  enable_data_handling: false,
396
625
  data_handling_mode: 'redact',
397
- violation_webhook: null,
626
+ violation_webhook: undefined,
398
627
  queue_full_mode: 'warn',
399
- queue_full_timeout_sec: null,
628
+ queue_full_timeout_sec: undefined,
400
629
  enable_attribution: false,
401
- attribution_company: null,
402
- attribution_role: null,
403
- attribution_email: null,
404
- attribution_source: null,
405
- attribution_use_case: null,
406
- attribution_team_size: null,
407
- attribution_business_owner: null,
630
+ attribution_company: undefined,
631
+ attribution_role: undefined,
632
+ attribution_email: undefined,
633
+ attribution_source: undefined,
634
+ attribution_use_case: undefined,
635
+ attribution_team_size: undefined,
636
+ attribution_business_owner: undefined,
408
637
  attribution_data_categories: [],
409
638
  telemetry_enabled: false,
410
639
  telemetry_send_data: false,
411
- telemetry_data_residency: null,
640
+ telemetry_data_residency: undefined,
412
641
  enable_audit_metadata: false,
413
- audit_use_case_name: null,
414
- audit_business_owner: null,
642
+ audit_use_case_name: undefined,
643
+ audit_business_owner: undefined,
415
644
  audit_data_categories: [],
416
645
  audit_risk_level: 'medium',
417
646
  audit_compliance_frameworks: [],
418
- audit_review_date: null,
419
- audit_reviewer: null,
420
- audit_notes: null,
647
+ audit_review_date: undefined,
648
+ audit_reviewer: undefined,
649
+ audit_notes: undefined,
421
650
  };
422
651
  console.log('Using smart defaults based on auto-detection...\n');
423
652
  if (answers.file_sink && answers.file_path) {
@@ -431,12 +660,19 @@ async function runInitWizard(configPath, format, assumeYes, force) {
431
660
  else {
432
661
  const rl = createInterface();
433
662
  try {
663
+ const selectedSinks = await askSinkSelection(rl, ['file']);
664
+ let stdoutSelected = selectedSinks.includes('stdout');
665
+ if (!stdoutSelected) {
666
+ stdoutSelected = await confirm(rl, 'Enable console output?', false);
667
+ }
434
668
  answers = {
435
669
  service_name: await ask(rl, 'Service name', detectedService),
436
670
  environment: await ask(rl, 'Environment (dev/poc/staging/production)', detectedEnv),
437
- stdout_sink: await confirm(rl, 'Enable stdout sink?', detectedEnv === 'dev' || detectedEnv === 'poc'),
438
- file_sink: await confirm(rl, 'Enable file sink?', true),
439
- https_sink: await confirm(rl, 'Enable HTTPS sink?', false),
671
+ stdout_sink: stdoutSelected,
672
+ stdout_format: 'pretty',
673
+ file_sink: selectedSinks.includes('file'),
674
+ file_rotation: 'none',
675
+ https_sink: selectedSinks.includes('https'),
440
676
  enable_policies: await confirm(rl, 'Configure model allowlist?', smartAllowlist.length > 0),
441
677
  allowlist: [],
442
678
  denylist: [],
@@ -489,7 +725,7 @@ async function runInitWizard(configPath, format, assumeYes, force) {
489
725
  if (answers.enable_policies) {
490
726
  const defaultAllowlist = smartAllowlist.length > 0
491
727
  ? smartAllowlist.join(',')
492
- : 'gpt-4*,claude-3-*';
728
+ : init_1.DEFAULT_ALLOWLIST_PATTERNS.join(',');
493
729
  answers.allowlist = parseList(await ask(rl, 'Allowlist patterns (comma-separated)', defaultAllowlist));
494
730
  answers.denylist = parseList(await ask(rl, 'Denylist patterns (comma-separated)', ''));
495
731
  }
@@ -533,7 +769,7 @@ async function runInitWizard(configPath, format, assumeYes, force) {
533
769
  while (true) {
534
770
  const timeout = await ask(rl, 'Queue full timeout (seconds, blank for no timeout)', '');
535
771
  if (!timeout) {
536
- answers.queue_full_timeout_sec = null;
772
+ answers.queue_full_timeout_sec = undefined;
537
773
  break;
538
774
  }
539
775
  const parsed = Number(timeout);
@@ -565,12 +801,12 @@ async function runInitWizard(configPath, format, assumeYes, force) {
565
801
  answers.telemetry_data_residency = (await ask(rl, 'Telemetry data residency (us/eu)', 'us')).trim();
566
802
  }
567
803
  else {
568
- answers.telemetry_data_residency = null;
804
+ answers.telemetry_data_residency = undefined;
569
805
  }
570
806
  }
571
807
  else {
572
808
  answers.telemetry_send_data = false;
573
- answers.telemetry_data_residency = null;
809
+ answers.telemetry_data_residency = undefined;
574
810
  }
575
811
  answers.enable_audit_metadata = await confirm(rl, 'Add audit metadata for compliance?', false);
576
812
  if (answers.enable_audit_metadata) {
@@ -590,10 +826,8 @@ async function runInitWizard(configPath, format, assumeYes, force) {
590
826
  rl.close();
591
827
  }
592
828
  }
593
- const config = buildConfig(answers);
594
- const output = format === 'json'
595
- ? JSON.stringify(config, null, 2)
596
- : yaml.dump(config, { sortKeys: false, noRefs: true });
829
+ const config = (0, init_1.buildWizardConfig)(answers);
830
+ const output = renderConfigOutput(config, format);
597
831
  fs.writeFileSync(configPath, output, 'utf-8');
598
832
  console.log(`\nMonora config written to ${configPath}`);
599
833
  console.log('\n=== Next Steps ===\n');
@@ -607,6 +841,10 @@ async function runInitWizard(configPath, format, assumeYes, force) {
607
841
  console.log(` import { init } from 'monora-ai';`);
608
842
  console.log(` init({ configPath: '${configPath}' });`);
609
843
  console.log('');
844
+ console.log('Generate reports with:');
845
+ console.log(' npx monora-ai report --input ./monora_events.jsonl --output monora_report.json');
846
+ console.log(' (If rotation is enabled, use ./monora_events.latest.jsonl)');
847
+ console.log('');
610
848
  if (detectedSdks.length > 0) {
611
849
  console.log(`Detected SDKs (${detectedSdks.join(', ')}) will be auto-instrumented.`);
612
850
  }
@@ -614,11 +852,14 @@ async function runInitWizard(configPath, format, assumeYes, force) {
614
852
  function parseInitOptions(args) {
615
853
  const configPath = getFlagValue(args, '--path') || 'monora.yml';
616
854
  const format = getFlagValue(args, '--format') || 'yaml';
855
+ const preset = normalizeInitPreset(getFlagValue(args, '--preset'));
617
856
  return {
618
857
  path: configPath,
619
858
  format: format === 'json' ? 'json' : 'yaml',
620
859
  yes: hasFlag(args, '--yes'),
621
860
  force: hasFlag(args, '--force'),
861
+ advanced: hasFlag(args, '--advanced'),
862
+ preset,
622
863
  };
623
864
  }
624
865
  function parseReportOptions(args) {
@@ -664,6 +905,7 @@ function parseSecurityReviewOptions(args) {
664
905
  };
665
906
  }
666
907
  function parseTrustPackageOptions(args) {
908
+ const target = Number(getFlagValue(args, '--control-coverage-target') || '0.9');
667
909
  return {
668
910
  input: getFlagValue(args, '--input'),
669
911
  traceId: getFlagValue(args, '--trace-id'),
@@ -672,6 +914,28 @@ function parseTrustPackageOptions(args) {
672
914
  sign: getFlagValue(args, '--sign') || undefined,
673
915
  gpgKey: getFlagValue(args, '--gpg-key'),
674
916
  gpgHome: getFlagValue(args, '--gpg-home'),
917
+ evidenceManifest: getFlagValue(args, '--evidence-manifest'),
918
+ evidenceRuntime: hasFlag(args, '--evidence-runtime'),
919
+ evidenceStandard: getFlagValue(args, '--evidence-standard') || undefined,
920
+ evidenceNoLineage: hasFlag(args, '--evidence-no-lineage'),
921
+ evidenceNoHashChain: hasFlag(args, '--evidence-no-hash-chain'),
922
+ evidenceNoWorkflowState: hasFlag(args, '--evidence-no-workflow-state'),
923
+ evidenceNoAimsState: hasFlag(args, '--evidence-no-aims-state'),
924
+ controlCatalog: getFlagValue(args, '--control-catalog'),
925
+ controlStandard: (() => {
926
+ const raw = getFlagValue(args, '--control-standard');
927
+ if (!raw) {
928
+ return undefined;
929
+ }
930
+ const normalized = raw.trim().toUpperCase();
931
+ if (normalized !== 'ISO42001' && normalized !== 'SOC2' && normalized !== 'GDPR') {
932
+ throw new Error("Invalid --control-standard. Expected one of: ISO42001, SOC2, GDPR.");
933
+ }
934
+ return normalized;
935
+ })(),
936
+ controlWorkflowState: getFlagValue(args, '--control-workflow-state'),
937
+ controlCoverageTarget: Number.isFinite(target) ? target : 0.9,
938
+ controlCoverage: getFlagValue(args, '--control-coverage'),
675
939
  schema: !hasFlag(args, '--no-schema'),
676
940
  verify: !hasFlag(args, '--no-verify'),
677
941
  signatureVerify: !hasFlag(args, '--no-signature-verify'),
@@ -978,7 +1242,7 @@ async function runReport(options) {
978
1242
  verifySignatures(events, config);
979
1243
  }
980
1244
  const policies = config.policies || undefined;
981
- const report = (0, report_1.buildReport)(events, policies);
1245
+ const report = (0, report_1.buildReport)(events, policies, config.registry);
982
1246
  if (options.format === 'markdown') {
983
1247
  (0, report_1.writeMarkdown)(options.output, report);
984
1248
  }
@@ -1072,7 +1336,20 @@ async function runTrustPackage(options) {
1072
1336
  if (options.signatureVerify) {
1073
1337
  verifySignatures(events, config);
1074
1338
  }
1075
- let trustPackage = (0, trust_package_1.buildTrustPackage)(options.traceId, events, config);
1339
+ let trustPackage = (0, trust_package_1.buildTrustPackage)(options.traceId, events, config, {
1340
+ evidenceManifestPath: options.evidenceManifest,
1341
+ evidenceManifestAuto: options.evidenceRuntime,
1342
+ evidenceManifestStandard: options.evidenceStandard,
1343
+ evidenceManifestIncludeLineage: !options.evidenceNoLineage,
1344
+ evidenceManifestIncludeHashChain: !options.evidenceNoHashChain,
1345
+ evidenceManifestIncludeWorkflowState: !options.evidenceNoWorkflowState,
1346
+ evidenceManifestIncludeAimsState: !options.evidenceNoAimsState,
1347
+ controlCatalogPath: options.controlCatalog,
1348
+ controlCatalogStandard: options.controlStandard,
1349
+ controlWorkflowStatePath: options.controlWorkflowState,
1350
+ controlCoverageTarget: options.controlCoverageTarget,
1351
+ controlCoveragePath: options.controlCoverage,
1352
+ });
1076
1353
  if (options.sign) {
1077
1354
  if (options.sign !== 'gpg') {
1078
1355
  console.error(`Unsupported signing type: ${options.sign}`);
@@ -1093,6 +1370,342 @@ async function runTrustPackage(options) {
1093
1370
  (0, trust_package_1.writeTrustPackage)(options.output, trustPackage);
1094
1371
  console.log(`Trust package generated: ${options.output}`);
1095
1372
  }
1373
+ function loadAimsStateIfPresent(statePath) {
1374
+ if (!statePath) {
1375
+ return;
1376
+ }
1377
+ if (!fs.existsSync(statePath)) {
1378
+ return;
1379
+ }
1380
+ (0, aims_governance_1.loadAimsGovernanceState)(statePath, { replaceRuntime: true });
1381
+ }
1382
+ function saveAimsStateIfPresent(statePath) {
1383
+ if (!statePath) {
1384
+ return;
1385
+ }
1386
+ (0, aims_governance_1.exportAimsGovernanceState)(statePath);
1387
+ }
1388
+ function emitAimsJson(payload) {
1389
+ console.log(JSON.stringify(payload, null, 2));
1390
+ }
1391
+ async function runAims(args) {
1392
+ const subcommand = args[0];
1393
+ const subArgs = args.slice(1);
1394
+ if (!subcommand) {
1395
+ usage();
1396
+ process.exit(1);
1397
+ }
1398
+ const statePath = getFlagValue(subArgs, '--state');
1399
+ loadAimsStateIfPresent(statePath);
1400
+ const required = (flag) => {
1401
+ const value = getFlagValue(subArgs, flag);
1402
+ if (!value) {
1403
+ throw new Error(`Missing required flag: ${flag}`);
1404
+ }
1405
+ return value;
1406
+ };
1407
+ if (subcommand === 'summary') {
1408
+ emitAimsJson((0, aims_governance_1.getAimsGovernanceSummary)());
1409
+ return;
1410
+ }
1411
+ if (subcommand === 'export-state') {
1412
+ const outputPath = required('--output');
1413
+ const payload = (0, aims_governance_1.exportAimsGovernanceState)(outputPath);
1414
+ emitAimsJson({ state_type: payload.state_type, output: outputPath });
1415
+ return;
1416
+ }
1417
+ if (subcommand === 'import-state') {
1418
+ const inputPath = required('--input');
1419
+ const payload = (0, aims_governance_1.loadAimsGovernanceState)(inputPath, { replaceRuntime: true });
1420
+ const policyCount = Array.isArray(payload.policies) ? payload.policies.length : 0;
1421
+ const concernCount = Array.isArray(payload.concern_reports) ? payload.concern_reports.length : 0;
1422
+ emitAimsJson({
1423
+ input: inputPath,
1424
+ policies: policyCount,
1425
+ concerns: concernCount,
1426
+ });
1427
+ return;
1428
+ }
1429
+ if (subcommand === 'policy-create') {
1430
+ const policy = (0, aims_governance_1.createPolicyDocument)({
1431
+ policyId: required('--policy-id'),
1432
+ title: required('--title'),
1433
+ owner: required('--owner'),
1434
+ reviewFrequencyDays: Number(getFlagValue(subArgs, '--review-frequency-days') || '365'),
1435
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1436
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1437
+ });
1438
+ saveAimsStateIfPresent(statePath);
1439
+ emitAimsJson(policy);
1440
+ return;
1441
+ }
1442
+ if (subcommand === 'policy-add-version') {
1443
+ const version = (0, aims_governance_1.addPolicyVersion)({
1444
+ policyId: required('--policy-id'),
1445
+ changeSummary: required('--change-summary'),
1446
+ createdBy: required('--created-by'),
1447
+ content: getFlagValue(subArgs, '--content'),
1448
+ artifactPath: getFlagValue(subArgs, '--artifact-path'),
1449
+ requiredReviewers: parseOptionalList(getFlagValue(subArgs, '--required-reviewers')),
1450
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1451
+ });
1452
+ saveAimsStateIfPresent(statePath);
1453
+ emitAimsJson(version);
1454
+ return;
1455
+ }
1456
+ if (subcommand === 'policy-submit') {
1457
+ const version = (0, aims_governance_1.submitPolicyVersion)({
1458
+ policyId: required('--policy-id'),
1459
+ versionId: required('--version-id'),
1460
+ submittedBy: required('--submitted-by'),
1461
+ reviewerChain: parseOptionalList(getFlagValue(subArgs, '--reviewer-chain')),
1462
+ note: getFlagValue(subArgs, '--note'),
1463
+ });
1464
+ saveAimsStateIfPresent(statePath);
1465
+ emitAimsJson(version);
1466
+ return;
1467
+ }
1468
+ if (subcommand === 'policy-approve') {
1469
+ const version = (0, aims_governance_1.approvePolicyVersion)({
1470
+ policyId: required('--policy-id'),
1471
+ versionId: required('--version-id'),
1472
+ approver: required('--approver'),
1473
+ note: getFlagValue(subArgs, '--note'),
1474
+ force: hasFlag(subArgs, '--force'),
1475
+ });
1476
+ saveAimsStateIfPresent(statePath);
1477
+ emitAimsJson(version);
1478
+ return;
1479
+ }
1480
+ if (subcommand === 'policy-reject') {
1481
+ const version = (0, aims_governance_1.rejectPolicyVersion)({
1482
+ policyId: required('--policy-id'),
1483
+ versionId: required('--version-id'),
1484
+ reviewer: required('--reviewer'),
1485
+ note: required('--note'),
1486
+ });
1487
+ saveAimsStateIfPresent(statePath);
1488
+ emitAimsJson(version);
1489
+ return;
1490
+ }
1491
+ if (subcommand === 'policy-review') {
1492
+ const version = (0, aims_governance_1.recordPolicyReview)({
1493
+ policyId: required('--policy-id'),
1494
+ versionId: required('--version-id'),
1495
+ reviewer: required('--reviewer'),
1496
+ summary: required('--summary'),
1497
+ outcome: getFlagValue(subArgs, '--outcome') || 'accepted',
1498
+ });
1499
+ saveAimsStateIfPresent(statePath);
1500
+ emitAimsJson(version);
1501
+ return;
1502
+ }
1503
+ if (subcommand === 'policy-list') {
1504
+ emitAimsJson((0, aims_governance_1.listPolicyDocuments)());
1505
+ return;
1506
+ }
1507
+ if (subcommand === 'policy-get') {
1508
+ const policy = (0, aims_governance_1.getPolicyDocument)(required('--policy-id'));
1509
+ if (!policy) {
1510
+ throw new Error(`Policy not found: ${required('--policy-id')}`);
1511
+ }
1512
+ emitAimsJson(policy);
1513
+ return;
1514
+ }
1515
+ if (subcommand === 'policy-workflows') {
1516
+ const policyId = getFlagValue(subArgs, '--policy-id');
1517
+ const buildStatus = (policy) => {
1518
+ const workflowMap = { ...(policy.workflow_ids || {}) };
1519
+ if (Object.keys(workflowMap).length === 0) {
1520
+ const workflows = (0, control_backbone_1.listWorkflowTasks)({}).filter((workflow) => workflow.metadata?.policy_id === policy.policy_id);
1521
+ for (const workflow of workflows) {
1522
+ workflowMap[workflow.control_id] = workflow.workflow_id;
1523
+ }
1524
+ }
1525
+ const entries = Object.entries(workflowMap).sort(([a], [b]) => a.localeCompare(b)).map(([controlId, workflowId]) => {
1526
+ const workflow = (0, control_backbone_1.getWorkflowTask)(workflowId);
1527
+ if (!workflow) {
1528
+ return { control_id: controlId, workflow_id: workflowId, status: 'missing' };
1529
+ }
1530
+ return {
1531
+ control_id: controlId,
1532
+ workflow_id: workflow.workflow_id,
1533
+ status: workflow.status,
1534
+ owner: workflow.owner,
1535
+ due_at: workflow.due_at,
1536
+ updated_at: workflow.updated_at,
1537
+ };
1538
+ });
1539
+ return {
1540
+ policy_id: policy.policy_id,
1541
+ title: policy.title,
1542
+ owner: policy.owner,
1543
+ active_version_id: policy.active_version_id,
1544
+ workflows: entries,
1545
+ };
1546
+ };
1547
+ if (policyId) {
1548
+ const policy = (0, aims_governance_1.getPolicyDocument)(policyId);
1549
+ if (!policy) {
1550
+ throw new Error(`Policy not found: ${policyId}`);
1551
+ }
1552
+ emitAimsJson(buildStatus(policy));
1553
+ return;
1554
+ }
1555
+ emitAimsJson((0, aims_governance_1.listPolicyDocuments)().map((policy) => buildStatus(policy)));
1556
+ return;
1557
+ }
1558
+ if (subcommand === 'policy-approvals') {
1559
+ const policyId = getFlagValue(subArgs, '--policy-id');
1560
+ const versionId = getFlagValue(subArgs, '--version-id');
1561
+ if (versionId && !policyId) {
1562
+ throw new Error('--version-id requires --policy-id');
1563
+ }
1564
+ const policies = policyId ? [(0, aims_governance_1.getPolicyDocument)(policyId)] : (0, aims_governance_1.listPolicyDocuments)();
1565
+ const payload = policies.map((policy) => {
1566
+ if (!policy) {
1567
+ throw new Error(`Policy not found: ${policyId}`);
1568
+ }
1569
+ const versions = (policy.versions || [])
1570
+ .filter((version) => !versionId || version.version_id === versionId)
1571
+ .map((version) => ({
1572
+ version_id: version.version_id,
1573
+ version_number: version.version_number,
1574
+ status: version.status,
1575
+ submitted_at: version.submitted_at,
1576
+ approved_at: version.approved_at,
1577
+ approved_by: version.approved_by,
1578
+ required_reviewers: version.required_reviewers,
1579
+ approvals: version.approvals,
1580
+ review_history: version.review_history,
1581
+ }));
1582
+ return {
1583
+ policy_id: policy.policy_id,
1584
+ title: policy.title,
1585
+ owner: policy.owner,
1586
+ active_version_id: policy.active_version_id,
1587
+ versions,
1588
+ };
1589
+ });
1590
+ emitAimsJson(payload);
1591
+ return;
1592
+ }
1593
+ if (subcommand === 'policy-due') {
1594
+ emitAimsJson((0, aims_governance_1.getDuePolicyReviews)({
1595
+ referenceTime: getFlagValue(subArgs, '--reference-time'),
1596
+ }));
1597
+ return;
1598
+ }
1599
+ if (subcommand === 'context-record') {
1600
+ const record = (0, aims_governance_1.recordAimsContext)({
1601
+ scope: required('--scope'),
1602
+ approvedBy: required('--approved-by'),
1603
+ interestedParties: parseOptionalList(getFlagValue(subArgs, '--interested-parties')),
1604
+ internalIssues: parseOptionalList(getFlagValue(subArgs, '--internal-issues')),
1605
+ externalIssues: parseOptionalList(getFlagValue(subArgs, '--external-issues')),
1606
+ objectives: parseOptionalList(getFlagValue(subArgs, '--objectives')),
1607
+ reviewFrequencyDays: Number(getFlagValue(subArgs, '--review-frequency-days') || '365'),
1608
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1609
+ });
1610
+ saveAimsStateIfPresent(statePath);
1611
+ emitAimsJson(record);
1612
+ return;
1613
+ }
1614
+ if (subcommand === 'context-get') {
1615
+ emitAimsJson((0, aims_governance_1.getAimsContext)() || {});
1616
+ return;
1617
+ }
1618
+ if (subcommand === 'raci-register') {
1619
+ const entry = (0, aims_governance_1.registerRaciEntry)({
1620
+ functionName: required('--function-name'),
1621
+ owner: required('--owner'),
1622
+ accountable: parseOptionalList(required('--accountable')),
1623
+ responsible: parseOptionalList(required('--responsible')),
1624
+ consulted: parseOptionalList(getFlagValue(subArgs, '--consulted')),
1625
+ informed: parseOptionalList(getFlagValue(subArgs, '--informed')),
1626
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1627
+ notes: getFlagValue(subArgs, '--notes'),
1628
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1629
+ });
1630
+ saveAimsStateIfPresent(statePath);
1631
+ emitAimsJson(entry);
1632
+ return;
1633
+ }
1634
+ if (subcommand === 'raci-list') {
1635
+ emitAimsJson((0, aims_governance_1.listRaciEntries)());
1636
+ return;
1637
+ }
1638
+ if (subcommand === 'training-record') {
1639
+ const record = (0, aims_governance_1.recordGovernanceTraining)({
1640
+ userId: required('--user-id'),
1641
+ topic: required('--topic'),
1642
+ recordedBy: required('--recorded-by'),
1643
+ completedAt: getFlagValue(subArgs, '--completed-at'),
1644
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1645
+ notes: getFlagValue(subArgs, '--notes'),
1646
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1647
+ });
1648
+ saveAimsStateIfPresent(statePath);
1649
+ emitAimsJson(record);
1650
+ return;
1651
+ }
1652
+ if (subcommand === 'training-list') {
1653
+ emitAimsJson((0, aims_governance_1.listGovernanceTrainingRecords)());
1654
+ return;
1655
+ }
1656
+ if (subcommand === 'concern-file') {
1657
+ const report = (0, aims_governance_1.fileConcernReport)({
1658
+ title: required('--title'),
1659
+ description: required('--description'),
1660
+ reportedBy: required('--reported-by'),
1661
+ severity: getFlagValue(subArgs, '--severity') || 'medium',
1662
+ assignedTo: getFlagValue(subArgs, '--assigned-to'),
1663
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1664
+ tags: parseOptionalList(getFlagValue(subArgs, '--tags')),
1665
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1666
+ });
1667
+ saveAimsStateIfPresent(statePath);
1668
+ emitAimsJson(report);
1669
+ return;
1670
+ }
1671
+ if (subcommand === 'concern-update') {
1672
+ const report = (0, aims_governance_1.updateConcernReport)({
1673
+ concernId: required('--concern-id'),
1674
+ actor: required('--actor'),
1675
+ status: required('--status'),
1676
+ note: getFlagValue(subArgs, '--note'),
1677
+ assignedTo: getFlagValue(subArgs, '--assigned-to'),
1678
+ });
1679
+ saveAimsStateIfPresent(statePath);
1680
+ emitAimsJson(report);
1681
+ return;
1682
+ }
1683
+ if (subcommand === 'concern-resolve') {
1684
+ const report = (0, aims_governance_1.resolveConcernReport)({
1685
+ concernId: required('--concern-id'),
1686
+ resolvedBy: required('--resolved-by'),
1687
+ resolutionSummary: required('--resolution-summary'),
1688
+ close: !hasFlag(subArgs, '--no-close'),
1689
+ });
1690
+ saveAimsStateIfPresent(statePath);
1691
+ emitAimsJson(report);
1692
+ return;
1693
+ }
1694
+ if (subcommand === 'concern-list') {
1695
+ const status = getFlagValue(subArgs, '--status');
1696
+ emitAimsJson((0, aims_governance_1.listConcernReports)({ status: status }));
1697
+ return;
1698
+ }
1699
+ if (subcommand === 'concern-get') {
1700
+ const report = (0, aims_governance_1.getConcernReport)(required('--concern-id'));
1701
+ if (!report) {
1702
+ throw new Error(`Concern not found: ${required('--concern-id')}`);
1703
+ }
1704
+ emitAimsJson(report);
1705
+ return;
1706
+ }
1707
+ throw new Error(`Unsupported aims subcommand: ${subcommand}`);
1708
+ }
1096
1709
  async function runVerify(options) {
1097
1710
  if (!options.input) {
1098
1711
  usage();
@@ -1197,9 +1810,12 @@ async function runVerify(options) {
1197
1810
  async function runValidate(args) {
1198
1811
  const configPath = getFlagValue(args, '--config') || 'monora.yml';
1199
1812
  const asJson = hasFlag(args, '--json');
1813
+ const modeArg = normalizeValidationMode(getFlagValue(args, '--mode'));
1200
1814
  try {
1201
1815
  const config = (0, config_1.loadConfig)({ configPath });
1202
- const results = (0, diagnostics_1.validateConfig)(config);
1816
+ const env = config.defaults?.environment || 'dev';
1817
+ const mode = modeArg || (env === 'production' ? 'strict' : 'lenient');
1818
+ const results = (0, diagnostics_1.validateConfig)(config, { mode });
1203
1819
  const exitCode = (0, diagnostics_1.emitResults)(results, { json: asJson });
1204
1820
  process.exit(exitCode);
1205
1821
  }
@@ -1213,9 +1829,8 @@ async function runDoctor(args) {
1213
1829
  const asJson = hasFlag(args, '--json');
1214
1830
  const noNetwork = hasFlag(args, '--no-network');
1215
1831
  try {
1216
- const config = (0, config_1.loadConfig)({ configPath });
1217
- const results = (0, diagnostics_1.doctorChecks)(config, { checkNetwork: !noNetwork });
1218
- const exitCode = (0, diagnostics_1.emitResults)(results, { json: asJson });
1832
+ const results = await (0, doctor_1.doctorChecks)(configPath, { checkNetwork: !noNetwork });
1833
+ const exitCode = (0, doctor_1.emitDoctorResults)(results, { json: asJson });
1219
1834
  process.exit(exitCode);
1220
1835
  }
1221
1836
  catch (error) {
@@ -1223,6 +1838,49 @@ async function runDoctor(args) {
1223
1838
  process.exit(1);
1224
1839
  }
1225
1840
  }
1841
+ async function runConfigFix(args) {
1842
+ const configPath = getFlagValue(args, '--config') || 'monora.yml';
1843
+ const dryRun = hasFlag(args, '--dry-run');
1844
+ const noNetwork = hasFlag(args, '--no-network');
1845
+ try {
1846
+ const result = await (0, fix_1.fixConfigFile)(configPath, {
1847
+ dryRun,
1848
+ checkNetwork: !noNetwork,
1849
+ });
1850
+ if (!result.ok) {
1851
+ for (const error of result.errors) {
1852
+ console.error(`Error: ${error}`);
1853
+ }
1854
+ process.exit(1);
1855
+ }
1856
+ if (result.changes.length === 0) {
1857
+ console.log('No fixes required.');
1858
+ return;
1859
+ }
1860
+ console.log('Applied fixes:');
1861
+ for (const change of result.changes) {
1862
+ console.log(` - ${change}`);
1863
+ }
1864
+ if (result.warnings.length > 0) {
1865
+ console.log('Warnings:');
1866
+ for (const warning of result.warnings) {
1867
+ console.log(` - ${warning}`);
1868
+ }
1869
+ }
1870
+ if (dryRun) {
1871
+ console.log('\nDry run only (no files written).');
1872
+ return;
1873
+ }
1874
+ if (result.backupPath) {
1875
+ console.log(`Backup written to ${result.backupPath}`);
1876
+ }
1877
+ console.log(`Updated config saved to ${configPath}`);
1878
+ }
1879
+ catch (error) {
1880
+ console.error(`Error: ${error?.message || error}`);
1881
+ process.exit(1);
1882
+ }
1883
+ }
1226
1884
  async function runCompatReport(args) {
1227
1885
  const baselinePath = getFlagValue(args, '--baseline');
1228
1886
  const outputPath = getFlagValue(args, '--output');
@@ -1272,7 +1930,7 @@ async function runStandardsWizard(args) {
1272
1930
  const rl = acceptDefaults ? null : createInterface();
1273
1931
  let standard = standardArg;
1274
1932
  if (!standard && !acceptDefaults && rl) {
1275
- standard = await ask(rl, 'Which standard (SOC2, GDPR, ISO27001, custom)', 'SOC2');
1933
+ standard = await ask(rl, 'Which standard (SOC2, GDPR, ISO27001, ISO42001, custom)', 'SOC2');
1276
1934
  }
1277
1935
  const standardKey = (standard || 'SOC2').trim();
1278
1936
  let templatePath = templateArg || resolveStandardsTemplatePath(standardKey);
@@ -1605,6 +2263,415 @@ async function runStandardsCheck(args) {
1605
2263
  process.exit(1);
1606
2264
  }
1607
2265
  }
2266
+ function normalizeComplianceTargets(values) {
2267
+ const normalized = values
2268
+ .map((value) => value.trim().toLowerCase().replace(/-/g, '_'))
2269
+ .filter(Boolean);
2270
+ const invalid = normalized.filter((value) => !(0, complianceTargets_1.isFrameworkSupported)(value));
2271
+ if (invalid.length > 0) {
2272
+ throw new Error(`Unsupported compliance target(s): ${invalid.join(', ')}`);
2273
+ }
2274
+ return normalized;
2275
+ }
2276
+ async function runSchema(args) {
2277
+ const subcommand = args[0];
2278
+ const subArgs = args.slice(1);
2279
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
2280
+ console.log('Usage: npx monora-ai schema infer [options]');
2281
+ console.log(' infer --input <events.jsonl> --output <spec.json> [--model-name <name>] [--model-version <ver>] [--compliance-target <framework>]... [--sample-size <n>] [--no-pii] [--report <inference_report.json>] [--contract <schema_contract.json>]');
2282
+ process.exit(1);
2283
+ }
2284
+ if (subcommand !== 'infer') {
2285
+ console.error(`Unknown schema subcommand: ${subcommand}`);
2286
+ process.exit(1);
2287
+ }
2288
+ const inputPath = getFlagValue(subArgs, '--input');
2289
+ const outputPath = getFlagValue(subArgs, '--output');
2290
+ const modelName = getFlagValue(subArgs, '--model-name');
2291
+ const modelVersion = getFlagValue(subArgs, '--model-version') || '1.0.0';
2292
+ const sampleSizeRaw = getFlagValue(subArgs, '--sample-size');
2293
+ const sampleSize = sampleSizeRaw ? Number(sampleSizeRaw) : 100;
2294
+ const noPii = hasFlag(subArgs, '--no-pii');
2295
+ const reportPath = getFlagValue(subArgs, '--report');
2296
+ const contractPath = getFlagValue(subArgs, '--contract');
2297
+ if (!inputPath || !outputPath) {
2298
+ console.error('Error: --input and --output are required for schema infer.');
2299
+ process.exit(1);
2300
+ }
2301
+ if (!Number.isFinite(sampleSize) || sampleSize <= 0) {
2302
+ console.error('Error: --sample-size must be > 0.');
2303
+ process.exit(1);
2304
+ }
2305
+ let complianceTargets = [];
2306
+ try {
2307
+ complianceTargets = normalizeComplianceTargets(getFlagValues(subArgs, '--compliance-target'));
2308
+ }
2309
+ catch (error) {
2310
+ console.error(`Error: ${error?.message || error}`);
2311
+ process.exit(1);
2312
+ }
2313
+ try {
2314
+ const spec = (0, schemaInference_1.inferSchemaFromFile)(inputPath, {
2315
+ modelName: modelName || undefined,
2316
+ modelVersion,
2317
+ complianceTargets,
2318
+ detectPii: !noPii,
2319
+ sampleSize,
2320
+ });
2321
+ const outputResolved = path.resolve(outputPath);
2322
+ fs.mkdirSync(path.dirname(outputResolved), { recursive: true });
2323
+ fs.writeFileSync(outputResolved, JSON.stringify((0, spec_1.specToDict)(spec), null, 2), 'utf-8');
2324
+ console.log(`Wrote inferred schema spec to ${outputPath}`);
2325
+ if (contractPath) {
2326
+ const contractResolved = path.resolve(contractPath);
2327
+ fs.mkdirSync(path.dirname(contractResolved), { recursive: true });
2328
+ fs.writeFileSync(contractResolved, JSON.stringify((0, spec_1.specToSchemaContract)(spec), null, 2), 'utf-8');
2329
+ console.log(`Wrote schema contract to ${contractPath}`);
2330
+ }
2331
+ if (reportPath) {
2332
+ const reportResolved = path.resolve(reportPath);
2333
+ fs.mkdirSync(path.dirname(reportResolved), { recursive: true });
2334
+ const events = (0, schemaInference_1.loadEventsFromFile)(inputPath);
2335
+ const report = (0, schemaInference_1.generateInferenceReport)(events, sampleSize);
2336
+ fs.writeFileSync(reportResolved, JSON.stringify(report, null, 2), 'utf-8');
2337
+ console.log(`Wrote inference report to ${reportPath}`);
2338
+ }
2339
+ }
2340
+ catch (error) {
2341
+ console.error(`Error: ${error?.message || error}`);
2342
+ process.exit(1);
2343
+ }
2344
+ }
2345
+ async function runModel(args) {
2346
+ const subcommand = args[0];
2347
+ const subArgs = args.slice(1);
2348
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
2349
+ console.log('Usage: npx monora-ai model create [options]');
2350
+ console.log(' create --input <events.jsonl> --output <model.json> [--model-name <name>] [--model-version <ver>] [--compliance-target <framework>]... [--risk-category minimal|limited|high|unacceptable] [--intended-use <text>] [--owner <id>] [--tag <value>]... [--sample-size <n>] [--no-pii] [--config-out <monora.yml|json>] [--config-format yaml|json] [--contract-out <schema_contract.json>]');
2351
+ process.exit(1);
2352
+ }
2353
+ if (subcommand !== 'create') {
2354
+ console.error(`Unknown model subcommand: ${subcommand}`);
2355
+ process.exit(1);
2356
+ }
2357
+ const inputPath = getFlagValue(subArgs, '--input');
2358
+ const outputPath = getFlagValue(subArgs, '--output');
2359
+ const modelName = getFlagValue(subArgs, '--model-name') || 'unnamed-model';
2360
+ const modelVersion = getFlagValue(subArgs, '--model-version') || '1.0.0';
2361
+ const riskCategory = getFlagValue(subArgs, '--risk-category') || 'limited';
2362
+ const intendedUse = getFlagValue(subArgs, '--intended-use');
2363
+ const owner = getFlagValue(subArgs, '--owner');
2364
+ const sampleSizeRaw = getFlagValue(subArgs, '--sample-size');
2365
+ const sampleSize = sampleSizeRaw ? Number(sampleSizeRaw) : 100;
2366
+ const noPii = hasFlag(subArgs, '--no-pii');
2367
+ const configOut = getFlagValue(subArgs, '--config-out');
2368
+ const configFormat = (getFlagValue(subArgs, '--config-format') || 'yaml').toLowerCase();
2369
+ const contractOut = getFlagValue(subArgs, '--contract-out');
2370
+ if (!inputPath || !outputPath) {
2371
+ console.error('Error: --input and --output are required for model create.');
2372
+ process.exit(1);
2373
+ }
2374
+ if (!Number.isFinite(sampleSize) || sampleSize <= 0) {
2375
+ console.error('Error: --sample-size must be > 0.');
2376
+ process.exit(1);
2377
+ }
2378
+ if (!['minimal', 'limited', 'high', 'unacceptable'].includes(riskCategory)) {
2379
+ console.error("Error: --risk-category must be one of minimal|limited|high|unacceptable.");
2380
+ process.exit(1);
2381
+ }
2382
+ if (!['yaml', 'json'].includes(configFormat)) {
2383
+ console.error("Error: --config-format must be one of yaml|json.");
2384
+ process.exit(1);
2385
+ }
2386
+ let complianceTargets = [];
2387
+ let tags = [];
2388
+ try {
2389
+ complianceTargets = normalizeComplianceTargets(getFlagValues(subArgs, '--compliance-target'));
2390
+ tags = getFlagValues(subArgs, '--tag');
2391
+ }
2392
+ catch (error) {
2393
+ console.error(`Error: ${error?.message || error}`);
2394
+ process.exit(1);
2395
+ }
2396
+ try {
2397
+ const model = (0, model_1.modelFromData)({
2398
+ source: inputPath,
2399
+ modelName,
2400
+ modelVersion,
2401
+ complianceTargets,
2402
+ riskCategory: riskCategory,
2403
+ intendedUse: intendedUse || undefined,
2404
+ owner: owner || undefined,
2405
+ tags,
2406
+ detectPii: !noPii,
2407
+ sampleSize,
2408
+ });
2409
+ (0, model_1.saveModel)(model, outputPath);
2410
+ console.log(`Wrote model to ${outputPath}`);
2411
+ if (configOut) {
2412
+ (0, model_1.saveConfig)(model, configOut, configFormat);
2413
+ console.log(`Wrote generated config to ${configOut}`);
2414
+ }
2415
+ if (contractOut) {
2416
+ (0, model_1.saveSchemaContract)(model, contractOut);
2417
+ console.log(`Wrote schema contract to ${contractOut}`);
2418
+ }
2419
+ }
2420
+ catch (error) {
2421
+ console.error(`Error: ${error?.message || error}`);
2422
+ process.exit(1);
2423
+ }
2424
+ }
2425
+ async function runOnboard(args) {
2426
+ const subcommand = args[0];
2427
+ const subArgs = args.slice(1);
2428
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
2429
+ console.log('Usage: npx monora-ai onboard <init|validate|complete|status> [options]');
2430
+ console.log(' init [--config monora.yml] [--yes] [--force]');
2431
+ console.log(' validate [--config monora.yml] [--input events.jsonl] [--output result.json] [--pretty]');
2432
+ console.log(' complete [--config monora.yml] [--completed-by name] [--output result.json] [--pretty]');
2433
+ console.log(' status [--config monora.yml] [--pretty]');
2434
+ process.exit(1);
2435
+ }
2436
+ if (subcommand === 'init') {
2437
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2438
+ const acceptDefaults = hasFlag(subArgs, '--yes');
2439
+ const force = hasFlag(subArgs, '--force');
2440
+ if (fs.existsSync(configPath) && !force) {
2441
+ if (acceptDefaults) {
2442
+ console.error(`${configPath} already exists. Use --force to overwrite.`);
2443
+ process.exit(1);
2444
+ }
2445
+ const rl = createInterface();
2446
+ const overwrite = await confirm(rl, `${configPath} already exists. Overwrite?`, false);
2447
+ rl.close();
2448
+ if (!overwrite) {
2449
+ console.error('Aborted.');
2450
+ process.exit(1);
2451
+ }
2452
+ }
2453
+ const config = (0, config_1.loadConfig)({ configPath });
2454
+ const onboardingDefaults = (config.onboarding || {});
2455
+ let onboardingEnabled = true;
2456
+ let requiredInProd = true;
2457
+ let logsPath = String(onboardingDefaults?.artifacts?.production_logs_path || './monora_events.jsonl');
2458
+ let schemaPath = String(onboardingDefaults?.artifacts?.schema_contract_path || './onboarding/schema_contract.json');
2459
+ let datasetSamplePath = null;
2460
+ let baselineReportsDir = String(onboardingDefaults?.artifacts?.baseline_reports_dir || './monora_reports/onboarding');
2461
+ let standards = ['SOC2', 'GDPR', 'ISO27001', 'ISO42001'];
2462
+ let bundles = ['core_observability', 'soc2_access', 'gdpr_privacy', 'iso27001_security'];
2463
+ let toggles = {
2464
+ identity_tracking: true,
2465
+ risk_tracking: true,
2466
+ bias_tracking: false,
2467
+ oversight_tracking: true,
2468
+ data_governance_tracking: true,
2469
+ lifecycle_tracking: true,
2470
+ };
2471
+ let roles = {
2472
+ inputs: ['body.prompt'],
2473
+ outputs: ['body.response'],
2474
+ metadata: ['event_type', 'service_name', 'timestamp'],
2475
+ identifiers: ['event_id', 'trace_id', 'span_id'],
2476
+ };
2477
+ if (!acceptDefaults) {
2478
+ const rl = createInterface();
2479
+ try {
2480
+ onboardingEnabled = await confirm(rl, 'Enable onboarding?', true);
2481
+ requiredInProd = await confirm(rl, 'Require completed onboarding in production?', true);
2482
+ logsPath = await ask(rl, 'Production logs path', logsPath);
2483
+ schemaPath = await ask(rl, 'Schema contract path', schemaPath);
2484
+ const datasetRaw = (await ask(rl, 'Dataset sample path (optional)', '')).trim();
2485
+ datasetSamplePath = datasetRaw || null;
2486
+ baselineReportsDir = await ask(rl, 'Baseline reports output directory', baselineReportsDir);
2487
+ standards = parseOptionalList(await ask(rl, 'Standards (comma-separated)', 'SOC2,GDPR,ISO27001,ISO42001'));
2488
+ if (standards.length === 0) {
2489
+ standards = ['SOC2', 'GDPR', 'ISO27001', 'ISO42001'];
2490
+ }
2491
+ bundles = parseOptionalList(await ask(rl, 'Enrichment bundles (comma-separated)', 'core_observability,soc2_access,gdpr_privacy,iso27001_security'));
2492
+ if (bundles.length === 0) {
2493
+ bundles = ['core_observability', 'soc2_access', 'gdpr_privacy', 'iso27001_security'];
2494
+ }
2495
+ toggles = {
2496
+ identity_tracking: await confirm(rl, 'Enable identity tracking?', true),
2497
+ risk_tracking: await confirm(rl, 'Enable risk tracking?', true),
2498
+ bias_tracking: await confirm(rl, 'Enable bias tracking?', false),
2499
+ oversight_tracking: await confirm(rl, 'Enable oversight tracking?', true),
2500
+ data_governance_tracking: await confirm(rl, 'Enable data governance tracking?', true),
2501
+ lifecycle_tracking: await confirm(rl, 'Enable lifecycle tracking?', true),
2502
+ };
2503
+ const inputs = parseOptionalList(await ask(rl, 'Model spec input fields (comma-separated)', 'body.prompt'));
2504
+ const outputs = parseOptionalList(await ask(rl, 'Model spec output fields (comma-separated)', 'body.response'));
2505
+ const metadata = parseOptionalList(await ask(rl, 'Model spec metadata fields (comma-separated)', 'event_type,service_name,timestamp'));
2506
+ const identifiers = parseOptionalList(await ask(rl, 'Model spec identifiers (comma-separated)', 'event_id,trace_id,span_id'));
2507
+ roles = {
2508
+ inputs: inputs.length > 0 ? inputs : ['body.prompt'],
2509
+ outputs: outputs.length > 0 ? outputs : ['body.response'],
2510
+ metadata: metadata.length > 0 ? metadata : ['event_type', 'service_name', 'timestamp'],
2511
+ identifiers: identifiers.length > 0 ? identifiers : ['event_id', 'trace_id', 'span_id'],
2512
+ };
2513
+ }
2514
+ finally {
2515
+ rl.close();
2516
+ }
2517
+ }
2518
+ else {
2519
+ const enrichmentsDefaults = (config.enrichments || {});
2520
+ const bundlesDefault = Array.isArray(enrichmentsDefaults.bundles)
2521
+ ? enrichmentsDefaults.bundles
2522
+ : bundles;
2523
+ bundles = bundlesDefault.map((value) => String(value).trim()).filter(Boolean);
2524
+ if (bundles.length === 0) {
2525
+ bundles = ['core_observability', 'soc2_access', 'gdpr_privacy', 'iso27001_security'];
2526
+ }
2527
+ const toggleDefaults = enrichmentsDefaults.toggles && typeof enrichmentsDefaults.toggles === 'object'
2528
+ ? enrichmentsDefaults.toggles
2529
+ : {};
2530
+ toggles = {
2531
+ identity_tracking: Boolean(toggleDefaults.identity_tracking ?? toggles.identity_tracking),
2532
+ risk_tracking: Boolean(toggleDefaults.risk_tracking ?? toggles.risk_tracking),
2533
+ bias_tracking: Boolean(toggleDefaults.bias_tracking ?? toggles.bias_tracking),
2534
+ oversight_tracking: Boolean(toggleDefaults.oversight_tracking ?? toggles.oversight_tracking),
2535
+ data_governance_tracking: Boolean(toggleDefaults.data_governance_tracking ?? toggles.data_governance_tracking),
2536
+ lifecycle_tracking: Boolean(toggleDefaults.lifecycle_tracking ?? toggles.lifecycle_tracking),
2537
+ };
2538
+ }
2539
+ config.onboarding = {
2540
+ enabled: onboardingEnabled,
2541
+ required_in_production: requiredInProd,
2542
+ status: 'draft',
2543
+ standards,
2544
+ artifacts: {
2545
+ production_logs_path: logsPath,
2546
+ schema_contract_path: schemaPath,
2547
+ dataset_sample_path: datasetSamplePath,
2548
+ baseline_reports_dir: baselineReportsDir,
2549
+ },
2550
+ validation: {
2551
+ min_log_records: 100,
2552
+ required_field_presence_threshold: 0.95,
2553
+ type_conformance_threshold: 0.90,
2554
+ },
2555
+ completion: {
2556
+ completed_at: null,
2557
+ completed_by: null,
2558
+ last_validated_at: null,
2559
+ },
2560
+ };
2561
+ config.model_spec = (0, onboarding_1.buildModelSpec)({
2562
+ schemaRef: schemaPath,
2563
+ roles,
2564
+ });
2565
+ config.enrichments = {
2566
+ profile: 'recommended',
2567
+ bundles,
2568
+ toggles,
2569
+ };
2570
+ const enrichmentPlan = (0, onboarding_1.resolveEnrichmentPlan)(config, { apply: true });
2571
+ const ext = path.extname(configPath).toLowerCase();
2572
+ const raw = ext === '.json'
2573
+ ? JSON.stringify(config, null, 2)
2574
+ : yaml.dump(config, { sortKeys: false });
2575
+ fs.writeFileSync(configPath, raw, 'utf-8');
2576
+ const configDir = path.dirname(path.resolve(configPath));
2577
+ const schemaAbs = path.resolve(configDir, schemaPath);
2578
+ fs.mkdirSync(path.dirname(schemaAbs), { recursive: true });
2579
+ if (!fs.existsSync(schemaAbs)) {
2580
+ const schemaTemplate = {
2581
+ schema: {
2582
+ type: 'object',
2583
+ properties: {
2584
+ body: {
2585
+ type: 'object',
2586
+ properties: {
2587
+ prompt: { type: 'string' },
2588
+ response: { type: 'string' },
2589
+ },
2590
+ },
2591
+ },
2592
+ },
2593
+ roles,
2594
+ };
2595
+ fs.writeFileSync(schemaAbs, JSON.stringify(schemaTemplate, null, 2), 'utf-8');
2596
+ }
2597
+ try {
2598
+ const state = (0, runtime_1.getState)();
2599
+ if (state && typeof state.emitInternal === 'function') {
2600
+ state.emitInternal({
2601
+ event_type: 'onboarding_started',
2602
+ body: {
2603
+ config_path: configPath,
2604
+ standards,
2605
+ schema_contract_path: schemaPath,
2606
+ bundles,
2607
+ },
2608
+ purpose: 'governance',
2609
+ });
2610
+ }
2611
+ }
2612
+ catch {
2613
+ // no-op
2614
+ }
2615
+ console.log(`Onboarding config initialized in ${configPath}`);
2616
+ console.log(`Schema contract template: ${schemaAbs}`);
2617
+ if (Array.isArray(enrichmentPlan.unapplied_settings) && enrichmentPlan.unapplied_settings.length > 0) {
2618
+ console.log(`Warning: unresolved enrichment settings: ${enrichmentPlan.unapplied_settings.length}`);
2619
+ }
2620
+ return;
2621
+ }
2622
+ if (subcommand === 'validate') {
2623
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2624
+ const inputPathOverride = getFlagValue(subArgs, '--input');
2625
+ const outputPath = getFlagValue(subArgs, '--output');
2626
+ const pretty = hasFlag(subArgs, '--pretty');
2627
+ const result = (0, onboarding_1.validateOnboarding)({
2628
+ configPath,
2629
+ inputPathOverride: inputPathOverride || undefined,
2630
+ persist: true,
2631
+ });
2632
+ const output = JSON.stringify(result, null, pretty ? 2 : undefined);
2633
+ if (outputPath) {
2634
+ fs.writeFileSync(outputPath, output, 'utf-8');
2635
+ }
2636
+ else {
2637
+ console.log(output);
2638
+ }
2639
+ if (result.status !== 'validated') {
2640
+ process.exit(1);
2641
+ }
2642
+ return;
2643
+ }
2644
+ if (subcommand === 'complete') {
2645
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2646
+ const completedBy = getFlagValue(subArgs, '--completed-by');
2647
+ const outputPath = getFlagValue(subArgs, '--output');
2648
+ const pretty = hasFlag(subArgs, '--pretty');
2649
+ const result = (0, onboarding_1.completeOnboarding)({
2650
+ configPath,
2651
+ completedBy: completedBy || undefined,
2652
+ });
2653
+ const output = JSON.stringify(result, null, pretty ? 2 : undefined);
2654
+ if (outputPath) {
2655
+ fs.writeFileSync(outputPath, output, 'utf-8');
2656
+ }
2657
+ else {
2658
+ console.log(output);
2659
+ }
2660
+ if (result.status !== 'completed') {
2661
+ process.exit(1);
2662
+ }
2663
+ return;
2664
+ }
2665
+ if (subcommand === 'status') {
2666
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2667
+ const pretty = hasFlag(subArgs, '--pretty');
2668
+ const result = (0, onboarding_1.getOnboardingStatus)({ configPath });
2669
+ console.log(JSON.stringify(result, null, pretty ? 2 : undefined));
2670
+ return;
2671
+ }
2672
+ console.error(`Unknown onboard subcommand: ${subcommand}`);
2673
+ process.exit(1);
2674
+ }
1608
2675
  const RETRY_QUEUE_STATS_FILENAME = '.monora_retry_queue_stats.json';
1609
2676
  function resolveRetryQueuePaths(config, overridePath) {
1610
2677
  const warnings = [];
@@ -1785,6 +2852,284 @@ async function runRetryQueue(args) {
1785
2852
  process.exit(1);
1786
2853
  }
1787
2854
  }
2855
+ async function runProductionCheck(args) {
2856
+ const configPath = getFlagValue(args, '--config') || 'monora.yml';
2857
+ const jsonOutput = hasFlag(args, '--json');
2858
+ const showFix = hasFlag(args, '--fix');
2859
+ // Detect environment
2860
+ const envDetection = (0, config_1.detectEnvironment)();
2861
+ const suggestedPreset = (0, config_1.suggestPreset)();
2862
+ // Load config
2863
+ let config;
2864
+ try {
2865
+ config = (0, config_1.loadConfig)({ configPath });
2866
+ }
2867
+ catch {
2868
+ config = (0, config_1.loadConfig)({});
2869
+ }
2870
+ const checks = [];
2871
+ // Check 1: Signing enabled
2872
+ const signingEnabled = config.signing?.enabled === true;
2873
+ checks.push({
2874
+ name: 'signing_enabled',
2875
+ passed: signingEnabled,
2876
+ message: signingEnabled
2877
+ ? 'Event signing is enabled'
2878
+ : 'Event signing is disabled - events cannot be verified for authenticity',
2879
+ fix: signingEnabled ? undefined : 'Set signing.enabled: true and configure signing.key_env or signing.key_file',
2880
+ });
2881
+ // Check 2: WAL enabled
2882
+ const walEnabled = config.wal?.enabled === true;
2883
+ checks.push({
2884
+ name: 'wal_enabled',
2885
+ passed: walEnabled,
2886
+ message: walEnabled
2887
+ ? 'Write-ahead log is enabled for crash resilience'
2888
+ : 'Write-ahead log is disabled - events may be lost on crash',
2889
+ fix: walEnabled ? undefined : 'Set wal.enabled: true',
2890
+ });
2891
+ // Check 3: Hash chain verification
2892
+ const verifyOnShutdown = config.immutability?.verify_on_shutdown === true;
2893
+ const verifyOnEmit = config.immutability?.verify_on_emit === true;
2894
+ const hasVerification = verifyOnShutdown || verifyOnEmit;
2895
+ checks.push({
2896
+ name: 'hash_verification',
2897
+ passed: hasVerification,
2898
+ message: hasVerification
2899
+ ? `Hash chain verification enabled (on_emit: ${verifyOnEmit}, on_shutdown: ${verifyOnShutdown})`
2900
+ : 'Hash chain verification is disabled - tampering may go undetected',
2901
+ fix: hasVerification ? undefined : 'Set immutability.verify_on_shutdown: true',
2902
+ });
2903
+ // Check 4: No stdout sink in production
2904
+ const sinks = config.sinks || [];
2905
+ const hasStdoutSink = sinks.some((s) => s.type === 'stdout');
2906
+ const stdoutOk = envDetection.environment !== 'production' || !hasStdoutSink;
2907
+ checks.push({
2908
+ name: 'no_stdout_in_production',
2909
+ passed: stdoutOk,
2910
+ message: stdoutOk
2911
+ ? hasStdoutSink
2912
+ ? 'Stdout sink is acceptable in non-production environment'
2913
+ : 'No stdout sink configured'
2914
+ : 'Stdout sink detected in production - events may be lost',
2915
+ fix: stdoutOk ? undefined : 'Replace stdout sink with file or https sink for production',
2916
+ });
2917
+ // Check 5: Has persistent sink
2918
+ const hasPersistentSink = sinks.some((s) => s.type === 'file' || s.type === 'https');
2919
+ checks.push({
2920
+ name: 'persistent_sink',
2921
+ passed: hasPersistentSink,
2922
+ message: hasPersistentSink
2923
+ ? 'Persistent sink (file or https) is configured'
2924
+ : 'No persistent sink configured - events will not be stored',
2925
+ fix: hasPersistentSink ? undefined : 'Add a file or https sink to persist events',
2926
+ });
2927
+ // Check 6: Environment explicitly set
2928
+ const envExplicit = config.defaults?.environment && config.defaults.environment !== 'dev';
2929
+ checks.push({
2930
+ name: 'environment_set',
2931
+ passed: !!envExplicit,
2932
+ message: envExplicit
2933
+ ? `Environment explicitly set to: ${config.defaults?.environment}`
2934
+ : 'Environment defaults to "dev" - consider setting explicitly',
2935
+ fix: envExplicit ? undefined : 'Set defaults.environment to your target environment',
2936
+ });
2937
+ // Check 7: Service name set
2938
+ const hasServiceName = !!config.defaults?.service_name;
2939
+ checks.push({
2940
+ name: 'service_name_set',
2941
+ passed: hasServiceName,
2942
+ message: hasServiceName
2943
+ ? `Service name set: ${config.defaults?.service_name}`
2944
+ : 'Service name not set - events will be harder to identify',
2945
+ fix: hasServiceName ? undefined : 'Set defaults.service_name to identify your service',
2946
+ });
2947
+ // Build result
2948
+ const passedCount = checks.filter((c) => c.passed).length;
2949
+ const result = {
2950
+ passed: passedCount === checks.length,
2951
+ environment: {
2952
+ detected: envDetection.environment,
2953
+ source: envDetection.source,
2954
+ confidence: envDetection.confidence,
2955
+ suggested_preset: suggestedPreset,
2956
+ },
2957
+ checks,
2958
+ summary: {
2959
+ total: checks.length,
2960
+ passed: passedCount,
2961
+ failed: checks.length - passedCount,
2962
+ },
2963
+ };
2964
+ if (jsonOutput) {
2965
+ console.log(JSON.stringify(result, null, 2));
2966
+ }
2967
+ else {
2968
+ console.log('\n=== Monora Production Readiness Check ===\n');
2969
+ console.log('Environment Detection:');
2970
+ console.log(` Detected: ${result.environment.detected}`);
2971
+ console.log(` Source: ${result.environment.source}`);
2972
+ console.log(` Confidence: ${result.environment.confidence}`);
2973
+ console.log(` Suggested preset: ${result.environment.suggested_preset}`);
2974
+ console.log('');
2975
+ console.log('Checks:');
2976
+ for (const check of checks) {
2977
+ const status = check.passed ? '✓' : '✗';
2978
+ const color = check.passed ? '\x1b[32m' : '\x1b[31m';
2979
+ const reset = '\x1b[0m';
2980
+ console.log(` ${color}${status}${reset} ${check.name}: ${check.message}`);
2981
+ if (!check.passed && showFix && check.fix) {
2982
+ console.log(` → Fix: ${check.fix}`);
2983
+ }
2984
+ }
2985
+ console.log('');
2986
+ console.log('Summary:');
2987
+ console.log(` Total: ${result.summary.total}`);
2988
+ console.log(` Passed: ${result.summary.passed}`);
2989
+ console.log(` Failed: ${result.summary.failed}`);
2990
+ console.log('');
2991
+ if (result.passed) {
2992
+ console.log('\x1b[32m✓ All production readiness checks passed!\x1b[0m');
2993
+ }
2994
+ else {
2995
+ console.log('\x1b[33m⚠ Some checks failed. Run with --fix to see remediation steps.\x1b[0m');
2996
+ }
2997
+ }
2998
+ if (!result.passed) {
2999
+ process.exit(1);
3000
+ }
3001
+ }
3002
+ async function runDetectEnv(args) {
3003
+ const jsonOutput = hasFlag(args, '--json');
3004
+ const detection = (0, config_1.detectEnvironment)();
3005
+ const suggested = (0, config_1.suggestPreset)();
3006
+ if (jsonOutput) {
3007
+ console.log(JSON.stringify({
3008
+ ...detection,
3009
+ suggested_preset: suggested,
3010
+ }, null, 2));
3011
+ }
3012
+ else {
3013
+ console.log(`Environment: ${detection.environment}`);
3014
+ console.log(`Source: ${detection.source}`);
3015
+ console.log(`Confidence: ${detection.confidence}`);
3016
+ console.log(`Suggested preset: ${suggested}`);
3017
+ if (Object.keys(detection.context || {}).length > 0) {
3018
+ console.log('Context:');
3019
+ for (const [key, value] of Object.entries(detection.context || {})) {
3020
+ console.log(` ${key}: ${value}`);
3021
+ }
3022
+ }
3023
+ }
3024
+ }
3025
+ function diffConfigs(from, to, prefix = '') {
3026
+ const diffs = [];
3027
+ const allKeys = new Set([...Object.keys(from), ...Object.keys(to)]);
3028
+ for (const key of allKeys) {
3029
+ const path = prefix ? `${prefix}.${key}` : key;
3030
+ const fromVal = from[key];
3031
+ const toVal = to[key];
3032
+ if (fromVal === undefined && toVal !== undefined) {
3033
+ diffs.push({ path, from: undefined, to: toVal, action: 'add' });
3034
+ }
3035
+ else if (fromVal !== undefined && toVal === undefined) {
3036
+ diffs.push({ path, from: fromVal, to: undefined, action: 'remove' });
3037
+ }
3038
+ else if (typeof fromVal === 'object' && typeof toVal === 'object' && fromVal !== null && toVal !== null && !Array.isArray(fromVal) && !Array.isArray(toVal)) {
3039
+ diffs.push(...diffConfigs(fromVal, toVal, path));
3040
+ }
3041
+ else if (JSON.stringify(fromVal) !== JSON.stringify(toVal)) {
3042
+ diffs.push({ path, from: fromVal, to: toVal, action: 'change' });
3043
+ }
3044
+ }
3045
+ return diffs;
3046
+ }
3047
+ const VALID_PRESETS = [
3048
+ 'minimal', 'dev', 'development', 'production', 'compliance', 'poc',
3049
+ 'strict_enterprise', 'default_secure', 'experimental', 'audit_first', 'low_latency'
3050
+ ];
3051
+ async function runUpgradePreset(args) {
3052
+ const fromPreset = getFlagValue(args, '--from');
3053
+ const toPreset = getFlagValue(args, '--to');
3054
+ const outputPath = getFlagValue(args, '--output');
3055
+ const jsonOutput = hasFlag(args, '--json');
3056
+ if (!fromPreset || !toPreset) {
3057
+ console.error('Error: --from and --to presets are required');
3058
+ console.error('Usage: monora upgrade-preset --from <preset> --to <preset>');
3059
+ console.error(`Valid presets: ${VALID_PRESETS.join(', ')}`);
3060
+ process.exit(1);
3061
+ }
3062
+ if (!VALID_PRESETS.includes(fromPreset)) {
3063
+ console.error(`Error: Invalid --from preset '${fromPreset}'`);
3064
+ console.error(`Valid presets: ${VALID_PRESETS.join(', ')}`);
3065
+ process.exit(1);
3066
+ }
3067
+ if (!VALID_PRESETS.includes(toPreset)) {
3068
+ console.error(`Error: Invalid --to preset '${toPreset}'`);
3069
+ console.error(`Valid presets: ${VALID_PRESETS.join(', ')}`);
3070
+ process.exit(1);
3071
+ }
3072
+ const fromConfig = (0, config_1.getPresetConfig)(fromPreset);
3073
+ const toConfig = (0, config_1.getPresetConfig)(toPreset);
3074
+ const diffs = diffConfigs(fromConfig, toConfig);
3075
+ const result = {
3076
+ from_preset: fromPreset,
3077
+ to_preset: toPreset,
3078
+ changes: diffs.map(d => ({
3079
+ path: d.path,
3080
+ action: d.action,
3081
+ from: d.from,
3082
+ to: d.to,
3083
+ })),
3084
+ summary: {
3085
+ total: diffs.length,
3086
+ added: diffs.filter(d => d.action === 'add').length,
3087
+ removed: diffs.filter(d => d.action === 'remove').length,
3088
+ changed: diffs.filter(d => d.action === 'change').length,
3089
+ },
3090
+ };
3091
+ if (jsonOutput) {
3092
+ console.log(JSON.stringify(result, null, 2));
3093
+ }
3094
+ else {
3095
+ console.log(`\n=== Upgrade from '${fromPreset}' to '${toPreset}' ===\n`);
3096
+ if (diffs.length === 0) {
3097
+ console.log('No configuration changes required.');
3098
+ }
3099
+ else {
3100
+ console.log('Configuration changes:\n');
3101
+ for (const diff of diffs) {
3102
+ const actionColor = diff.action === 'add' ? '\x1b[32m+' : diff.action === 'remove' ? '\x1b[31m-' : '\x1b[33m~';
3103
+ const reset = '\x1b[0m';
3104
+ console.log(`${actionColor} ${diff.path}${reset}`);
3105
+ if (diff.action === 'change') {
3106
+ console.log(` from: ${JSON.stringify(diff.from)}`);
3107
+ console.log(` to: ${JSON.stringify(diff.to)}`);
3108
+ }
3109
+ else if (diff.action === 'add') {
3110
+ console.log(` value: ${JSON.stringify(diff.to)}`);
3111
+ }
3112
+ else if (diff.action === 'remove') {
3113
+ console.log(` was: ${JSON.stringify(diff.from)}`);
3114
+ }
3115
+ }
3116
+ console.log(`\nSummary: ${result.summary.total} changes`);
3117
+ console.log(` Added: ${result.summary.added}`);
3118
+ console.log(` Removed: ${result.summary.removed}`);
3119
+ console.log(` Changed: ${result.summary.changed}`);
3120
+ }
3121
+ if (outputPath) {
3122
+ const ext = path.extname(outputPath).toLowerCase();
3123
+ const content = ext === '.json' ? JSON.stringify(toConfig, null, 2) : yaml.dump(toConfig);
3124
+ fs.writeFileSync(outputPath, content, 'utf-8');
3125
+ console.log(`\nWrote '${toPreset}' preset configuration to: ${outputPath}`);
3126
+ }
3127
+ else {
3128
+ console.log('\nTo apply this preset, run:');
3129
+ console.log(` monora upgrade-preset --from ${fromPreset} --to ${toPreset} --output monora.yml`);
3130
+ }
3131
+ }
3132
+ }
1788
3133
  async function main() {
1789
3134
  const parsed = parseArgs(process.argv);
1790
3135
  if (!parsed.command || parsed.command === '--help' || parsed.command === '-h') {
@@ -1799,6 +3144,15 @@ async function main() {
1799
3144
  await runDoctor(parsed.args);
1800
3145
  return;
1801
3146
  }
3147
+ if (parsed.command === 'config') {
3148
+ const subcommand = parsed.args[0];
3149
+ if (subcommand === 'fix') {
3150
+ await runConfigFix(parsed.args.slice(1));
3151
+ return;
3152
+ }
3153
+ usage();
3154
+ process.exit(1);
3155
+ }
1802
3156
  if (parsed.command === 'init') {
1803
3157
  const options = parseInitOptions(parsed.args);
1804
3158
  if (fs.existsSync(options.path) && !options.force && !options.yes) {
@@ -1810,7 +3164,12 @@ async function main() {
1810
3164
  process.exit(1);
1811
3165
  }
1812
3166
  }
1813
- await runInitWizard(options.path, options.format, options.yes, options.force);
3167
+ await runInitWizard(options.path, options.format, options.yes, options.force, options.advanced, options.preset);
3168
+ return;
3169
+ }
3170
+ // New 'start' command for zero-code instrumentation
3171
+ if (parsed.command === 'start') {
3172
+ await runStart(parsed.args);
1814
3173
  return;
1815
3174
  }
1816
3175
  if (parsed.command === 'report') {
@@ -1829,6 +3188,10 @@ async function main() {
1829
3188
  await runTrustPackage(parseTrustPackageOptions(parsed.args));
1830
3189
  return;
1831
3190
  }
3191
+ if (parsed.command === 'aims') {
3192
+ await runAims(parsed.args);
3193
+ return;
3194
+ }
1832
3195
  if (parsed.command === 'ai-act-report') {
1833
3196
  await runAIActReport(parseAIActReportOptions(parsed.args));
1834
3197
  return;
@@ -1869,6 +3232,30 @@ async function main() {
1869
3232
  await runStandardsCheck(parsed.args);
1870
3233
  return;
1871
3234
  }
3235
+ if (parsed.command === 'onboard') {
3236
+ await runOnboard(parsed.args);
3237
+ return;
3238
+ }
3239
+ if (parsed.command === 'schema') {
3240
+ await runSchema(parsed.args);
3241
+ return;
3242
+ }
3243
+ if (parsed.command === 'model') {
3244
+ await runModel(parsed.args);
3245
+ return;
3246
+ }
3247
+ if (parsed.command === 'production-check') {
3248
+ await runProductionCheck(parsed.args);
3249
+ return;
3250
+ }
3251
+ if (parsed.command === 'detect-env') {
3252
+ await runDetectEnv(parsed.args);
3253
+ return;
3254
+ }
3255
+ if (parsed.command === 'upgrade-preset') {
3256
+ await runUpgradePreset(parsed.args);
3257
+ return;
3258
+ }
1872
3259
  usage();
1873
3260
  }
1874
3261
  main().catch((err) => {