monora-ai 2.0.0 → 2.1.3

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 (202) hide show
  1. package/README.md +441 -150
  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 +269 -0
  12. package/dist/assessment.d.ts.map +1 -0
  13. package/dist/assessment.js +1232 -0
  14. package/dist/attestation.js +23 -1
  15. package/dist/attribution.d.ts +349 -0
  16. package/dist/attribution.d.ts.map +1 -0
  17. package/dist/attribution.js +987 -0
  18. package/dist/autodetect.d.ts +69 -1
  19. package/dist/autodetect.d.ts.map +1 -1
  20. package/dist/autodetect.js +644 -1
  21. package/dist/bias.d.ts +130 -0
  22. package/dist/bias.d.ts.map +1 -0
  23. package/dist/bias.js +223 -0
  24. package/dist/circuit_breaker.js +3 -3
  25. package/dist/cli/diagnostics.d.ts +5 -1
  26. package/dist/cli/diagnostics.d.ts.map +1 -1
  27. package/dist/cli/diagnostics.js +31 -8
  28. package/dist/cli/doctor.d.ts +25 -0
  29. package/dist/cli/doctor.d.ts.map +1 -0
  30. package/dist/cli/doctor.js +381 -0
  31. package/dist/cli/fix.d.ts +16 -0
  32. package/dist/cli/fix.d.ts.map +1 -0
  33. package/dist/cli/fix.js +284 -0
  34. package/dist/cli/init.d.ts +57 -0
  35. package/dist/cli/init.d.ts.map +1 -0
  36. package/dist/cli/init.js +205 -0
  37. package/dist/cli.js +1611 -126
  38. package/dist/complianceTargets.d.ts +111 -0
  39. package/dist/complianceTargets.d.ts.map +1 -0
  40. package/dist/complianceTargets.js +521 -0
  41. package/dist/config.d.ts +301 -17
  42. package/dist/config.d.ts.map +1 -1
  43. package/dist/config.js +428 -36
  44. package/dist/config_migrations.d.ts +41 -0
  45. package/dist/config_migrations.d.ts.map +1 -1
  46. package/dist/config_migrations.js +205 -0
  47. package/dist/config_schema.d.ts +2900 -731
  48. package/dist/config_schema.d.ts.map +1 -1
  49. package/dist/config_schema.js +257 -55
  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 +122 -0
  54. package/dist/control_backbone.d.ts.map +1 -0
  55. package/dist/control_backbone.js +698 -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 +32 -0
  63. package/dist/dispatcher.d.ts.map +1 -1
  64. package/dist/dispatcher.js +91 -4
  65. package/dist/events.d.ts.map +1 -1
  66. package/dist/events.js +38 -0
  67. package/dist/evidence_store.d.ts +103 -0
  68. package/dist/evidence_store.d.ts.map +1 -0
  69. package/dist/evidence_store.js +459 -0
  70. package/dist/executiveSummary.d.ts +65 -8
  71. package/dist/executiveSummary.d.ts.map +1 -1
  72. package/dist/executiveSummary.js +289 -26
  73. package/dist/identity.d.ts +143 -0
  74. package/dist/identity.d.ts.map +1 -0
  75. package/dist/identity.js +231 -0
  76. package/dist/impact-assessment.d.ts +350 -0
  77. package/dist/impact-assessment.d.ts.map +1 -0
  78. package/dist/impact-assessment.js +580 -0
  79. package/dist/index.d.ts +25 -5
  80. package/dist/index.d.ts.map +1 -1
  81. package/dist/index.js +300 -4
  82. package/dist/instrumentation.d.ts +1 -1
  83. package/dist/instrumentation.d.ts.map +1 -1
  84. package/dist/instrumentation.js +243 -27
  85. package/dist/integrations/anthropic.d.ts +3 -0
  86. package/dist/integrations/anthropic.d.ts.map +1 -1
  87. package/dist/integrations/anthropic.js +284 -79
  88. package/dist/integrations/governance.d.ts +33 -0
  89. package/dist/integrations/governance.d.ts.map +1 -0
  90. package/dist/integrations/governance.js +208 -0
  91. package/dist/integrations/langchain.d.ts +7 -0
  92. package/dist/integrations/langchain.d.ts.map +1 -1
  93. package/dist/integrations/langchain.js +387 -143
  94. package/dist/integrations/openai.d.ts +9 -0
  95. package/dist/integrations/openai.d.ts.map +1 -1
  96. package/dist/integrations/openai.js +673 -73
  97. package/dist/iso42001_consolidation.d.ts +16 -0
  98. package/dist/iso42001_consolidation.d.ts.map +1 -0
  99. package/dist/iso42001_consolidation.js +413 -0
  100. package/dist/iso42001_workflows.d.ts +263 -0
  101. package/dist/iso42001_workflows.d.ts.map +1 -0
  102. package/dist/iso42001_workflows.js +781 -0
  103. package/dist/lifecycle.d.ts +299 -0
  104. package/dist/lifecycle.d.ts.map +1 -0
  105. package/dist/lifecycle.js +624 -0
  106. package/dist/lineage.d.ts +2 -2
  107. package/dist/lineage.d.ts.map +1 -1
  108. package/dist/lineage.js +12 -17
  109. package/dist/middleware/express.d.ts.map +1 -1
  110. package/dist/middleware/express.js +33 -3
  111. package/dist/middleware/nextjs.d.ts.map +1 -1
  112. package/dist/middleware/nextjs.js +42 -68
  113. package/dist/model.d.ts +143 -0
  114. package/dist/model.d.ts.map +1 -0
  115. package/dist/model.js +371 -0
  116. package/dist/onboarding.d.ts +42 -0
  117. package/dist/onboarding.d.ts.map +1 -0
  118. package/dist/onboarding.js +1022 -0
  119. package/dist/oversight.d.ts +264 -0
  120. package/dist/oversight.d.ts.map +1 -0
  121. package/dist/oversight.js +497 -0
  122. package/dist/pdf_report.d.ts.map +1 -1
  123. package/dist/pdf_report.js +42 -21
  124. package/dist/presets.d.ts +88 -0
  125. package/dist/presets.d.ts.map +1 -0
  126. package/dist/presets.js +520 -0
  127. package/dist/propagation.d.ts.map +1 -1
  128. package/dist/propagation.js +34 -2
  129. package/dist/quotas.d.ts +171 -0
  130. package/dist/quotas.d.ts.map +1 -0
  131. package/dist/quotas.js +259 -0
  132. package/dist/register.d.ts +13 -0
  133. package/dist/register.d.ts.map +1 -0
  134. package/dist/register.js +99 -0
  135. package/dist/registry.d.ts +1 -0
  136. package/dist/registry.d.ts.map +1 -1
  137. package/dist/registry.js +7 -0
  138. package/dist/registryData.json +43 -6
  139. package/dist/report.d.ts +2 -1
  140. package/dist/report.d.ts.map +1 -1
  141. package/dist/report.js +189 -2
  142. package/dist/reporting.d.ts +125 -0
  143. package/dist/reporting.d.ts.map +1 -1
  144. package/dist/reporting.js +196 -5
  145. package/dist/resources.d.ts +285 -0
  146. package/dist/resources.d.ts.map +1 -0
  147. package/dist/resources.js +643 -0
  148. package/dist/risk.d.ts +120 -0
  149. package/dist/risk.d.ts.map +1 -0
  150. package/dist/risk.js +220 -0
  151. package/dist/runtime.d.ts +74 -1
  152. package/dist/runtime.d.ts.map +1 -1
  153. package/dist/runtime.js +598 -22
  154. package/dist/schemaInference.d.ts +92 -0
  155. package/dist/schemaInference.d.ts.map +1 -0
  156. package/dist/schemaInference.js +466 -0
  157. package/dist/schema_validation.js +2 -2
  158. package/dist/schemas/config.schema.json +169 -6
  159. package/dist/schemas/event.schema.json +4 -0
  160. package/dist/security_report.js +4 -4
  161. package/dist/signing.d.ts +1 -1
  162. package/dist/signing.d.ts.map +1 -1
  163. package/dist/signing.js +4 -0
  164. package/dist/sinks/file.d.ts +19 -1
  165. package/dist/sinks/file.d.ts.map +1 -1
  166. package/dist/sinks/file.js +82 -13
  167. package/dist/sinks/https.d.ts +10 -0
  168. package/dist/sinks/https.d.ts.map +1 -1
  169. package/dist/sinks/https.js +76 -16
  170. package/dist/sinks/stdout.d.ts +1 -0
  171. package/dist/sinks/stdout.d.ts.map +1 -1
  172. package/dist/sinks/stdout.js +12 -1
  173. package/dist/spec.d.ts +159 -0
  174. package/dist/spec.d.ts.map +1 -0
  175. package/dist/spec.js +391 -0
  176. package/dist/stakeholders.d.ts +199 -0
  177. package/dist/stakeholders.d.ts.map +1 -0
  178. package/dist/stakeholders.js +398 -0
  179. package/dist/standards.d.ts.map +1 -1
  180. package/dist/standards.js +160 -2
  181. package/dist/standards_ingest.d.ts +2 -2
  182. package/dist/standards_ingest.d.ts.map +1 -1
  183. package/dist/standards_ingest.js +105 -23
  184. package/dist/streaming.d.ts.map +1 -1
  185. package/dist/streaming.js +7 -2
  186. package/dist/telemetry.d.ts +16 -2
  187. package/dist/telemetry.d.ts.map +1 -1
  188. package/dist/telemetry.js +79 -14
  189. package/dist/templates/controls/iso42001_control_catalog.json +1443 -0
  190. package/dist/traced_emitter.d.ts +3 -0
  191. package/dist/traced_emitter.d.ts.map +1 -1
  192. package/dist/traced_emitter.js +142 -25
  193. package/dist/trust_package.d.ts +21 -1
  194. package/dist/trust_package.d.ts.map +1 -1
  195. package/dist/trust_package.js +101 -4
  196. package/dist/verify.d.ts.map +1 -1
  197. package/dist/verify.js +9 -2
  198. package/dist/wal.d.ts.map +1 -1
  199. package/dist/wal.js +2 -1
  200. package/package.json +14 -1
  201. package/scripts/postinstall.js +119 -97
  202. package/templates/controls/iso42001_control_catalog.json +1443 -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] [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 {
@@ -191,8 +330,7 @@ function checkFileWritable(filePath) {
191
330
  try {
192
331
  const dir = path.dirname(filePath) || '.';
193
332
  fs.mkdirSync(dir, { recursive: true });
194
- const handle = fs.openSync(filePath, 'a');
195
- fs.closeSync(handle);
333
+ fs.accessSync(dir, fs.constants.W_OK);
196
334
  return { ok: true };
197
335
  }
198
336
  catch (error) {
@@ -221,92 +359,228 @@ async function testHttpEndpoint(endpoint, headers, label) {
221
359
  console.warn(`Warning: test POST to ${label} failed: ${message}`);
222
360
  }
223
361
  }
224
- function buildConfig(answers) {
225
- const config = (0, config_1.loadConfig)({ envPrefix: 'MONORA_WIZARD_' });
226
- config.defaults = {
227
- ...config.defaults,
228
- service_name: answers.service_name,
229
- environment: answers.environment,
230
- };
231
- const sinks = [];
232
- if (answers.stdout_sink) {
233
- sinks.push({ type: 'stdout', format: 'json' });
234
- }
235
- if (answers.file_sink) {
236
- sinks.push({
237
- type: 'file',
238
- path: answers.file_path || './monora_events.jsonl',
239
- rotation: 'daily',
240
- max_size_mb: 100,
241
- batch_size: 100,
242
- flush_interval_sec: 5.0,
243
- });
362
+ /**
363
+ * Streamlined 3-question wizard for quick setup.
364
+ * Uses AI-powered detection for smart defaults.
365
+ */
366
+ async function runStreamlinedWizard(configPath, format, assumeYes) {
367
+ console.log('\n\x1b[36m=== Monora Setup ===\x1b[0m\n');
368
+ console.log('Analyzing your project...\n');
369
+ // Run comprehensive detection
370
+ const detection = (0, autodetect_1.detectFramework)();
371
+ const serviceName = (0, autodetect_1.detectServiceName)() || 'monora-app';
372
+ const env = (0, autodetect_1.detectEnvironment)();
373
+ // Display detection results
374
+ console.log('\x1b[32mDetected:\x1b[0m');
375
+ console.log(` Service: ${serviceName}`);
376
+ if (detection.framework) {
377
+ console.log(` Framework: ${detection.framework}`);
378
+ }
379
+ console.log(` Environment: ${env}`);
380
+ if (detection.aiSdks.length > 0) {
381
+ console.log(` AI SDKs: ${detection.aiSdks.map(s => s.name).join(', ')}`);
382
+ }
383
+ if (detection.cloudPlatform) {
384
+ console.log(` Platform: ${detection.cloudPlatform}`);
385
+ }
386
+ if (detection.typescript) {
387
+ console.log(` TypeScript: yes`);
244
388
  }
245
- if (answers.https_sink && answers.https_endpoint) {
246
- const headers = {};
247
- if (answers.https_auth_header) {
248
- headers.Authorization = answers.https_auth_header;
389
+ console.log('');
390
+ // Run AI analysis if API key available
391
+ let aiAnalysis = null;
392
+ const hasAIKey = process.env.ANTHROPIC_API_KEY || process.env.OPENAI_API_KEY;
393
+ const aiAnalysisEnabled = ['true', '1', 'yes'].includes(String(process.env.MONORA_AI_ANALYSIS_ENABLED || '').toLowerCase());
394
+ if (hasAIKey && aiAnalysisEnabled) {
395
+ console.log('Running AI-powered analysis...');
396
+ aiAnalysis = await (0, autodetect_1.analyzeProjectWithAI)();
397
+ if (aiAnalysis) {
398
+ console.log(`\x1b[33mAI suggests:\x1b[0m ${aiAnalysis.reasoning}`);
399
+ if (aiAnalysis.complianceHints.length > 0) {
400
+ console.log(` Compliance: ${aiAnalysis.complianceHints.join(', ')}`);
401
+ }
249
402
  }
250
- sinks.push({
251
- type: 'https',
252
- endpoint: answers.https_endpoint,
253
- headers,
254
- batch_size: 50,
255
- timeout_sec: 10.0,
256
- retry_attempts: 3,
257
- backoff_base_sec: 0.5,
258
- });
403
+ console.log('');
259
404
  }
260
- config.sinks = sinks.length > 0 ? sinks : [{ type: 'stdout', format: 'json' }];
261
- config.policies = {
262
- ...config.policies,
263
- model_allowlist: answers.allowlist || [],
264
- model_denylist: answers.denylist || [],
265
- enforce: true,
266
- };
267
- config.instrumentation = {
268
- ...config.instrumentation,
269
- enabled: answers.enable_instrumentation,
270
- default_purpose: answers.instrumentation_purpose,
271
- };
272
- config.data_handling = {
273
- ...config.data_handling,
274
- enabled: answers.enable_data_handling,
275
- mode: (answers.data_handling_mode || 'redact'),
276
- rules: answers.enable_data_handling
277
- ? [
278
- {
279
- name: 'email',
280
- pattern: '[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}',
281
- replace: '[REDACTED_EMAIL]',
282
- classifications: ['confidential', 'secret'],
283
- apply_to: ['request', 'response'],
284
- },
285
- ]
286
- : [],
287
- };
288
- config.alerts = {
289
- ...config.alerts,
290
- violation_webhook: answers.violation_webhook || undefined,
291
- headers: answers.alerts_auth_header ? { Authorization: answers.alerts_auth_header } : {},
292
- };
293
- config.error_handling = {
294
- ...config.error_handling,
295
- queue_full_mode: answers.queue_full_mode,
296
- };
297
- config.buffering = {
298
- ...config.buffering,
299
- queue_full_timeout_sec: answers.queue_full_timeout_sec === undefined ? config.buffering?.queue_full_timeout_sec : answers.queue_full_timeout_sec,
405
+ else if (hasAIKey && !aiAnalysisEnabled) {
406
+ console.log('AI analysis is disabled. Set MONORA_AI_ANALYSIS_ENABLED=true to enable it.\n');
407
+ }
408
+ // Collect 3 required questions
409
+ let email = '';
410
+ let company = '';
411
+ let role = '';
412
+ if (assumeYes) {
413
+ // Use environment variables or empty
414
+ email = process.env.MONORA_EMAIL || '';
415
+ company = process.env.MONORA_COMPANY || '';
416
+ role = process.env.MONORA_ROLE || '';
417
+ console.log('Using environment variables for attribution...');
418
+ }
419
+ else {
420
+ const rl = createInterface();
421
+ try {
422
+ console.log('\x1b[36mQuick setup (3 questions):\x1b[0m');
423
+ email = (await ask(rl, ' Work email (for updates)', '')).trim();
424
+ company = (await ask(rl, ' Company name', '')).trim();
425
+ role = (await ask(rl, ' Your role', '')).trim();
426
+ }
427
+ finally {
428
+ rl.close();
429
+ }
430
+ }
431
+ console.log('');
432
+ // Build smart configuration
433
+ const config = (0, autodetect_1.buildSmartConfig)(detection, aiAnalysis, { email, company, role });
434
+ // Write configuration
435
+ const output = renderConfigOutput(config, format);
436
+ fs.writeFileSync(configPath, output, 'utf-8');
437
+ console.log(`\x1b[32mConfiguration saved to ${configPath}\x1b[0m\n`);
438
+ // Clear next steps
439
+ console.log('\x1b[36m=== Next Steps ===\x1b[0m\n');
440
+ console.log('To start tracing with zero code changes:');
441
+ console.log('\x1b[33m npx monora-ai start\x1b[0m\n');
442
+ console.log('Or wrap your existing command:');
443
+ console.log('\x1b[33m npx monora-ai start -- npm run dev\x1b[0m\n');
444
+ console.log('Or add to package.json scripts:');
445
+ console.log(' "scripts": {');
446
+ console.log(' "dev": "npx monora-ai start -- node server.js"');
447
+ console.log(' }\n');
448
+ if (detection.aiSdks.length > 0) {
449
+ console.log(`Auto-instrumentation enabled for: ${detection.aiSdks.map(s => s.name).join(', ')}`);
450
+ }
451
+ console.log('\nFor advanced configuration, run: \x1b[33mnpx monora-ai init --advanced\x1b[0m');
452
+ }
453
+ /**
454
+ * Run a command with Monora instrumentation enabled.
455
+ * Zero-code instrumentation using NODE_OPTIONS.
456
+ */
457
+ async function runStart(args) {
458
+ const { spawn } = await Promise.resolve().then(() => __importStar(require('child_process')));
459
+ // Find the separator '--' for the user command
460
+ const separatorIndex = args.indexOf('--');
461
+ let userCommand;
462
+ if (separatorIndex >= 0) {
463
+ userCommand = args.slice(separatorIndex + 1);
464
+ }
465
+ else if (args.length > 0) {
466
+ userCommand = args;
467
+ }
468
+ else {
469
+ // No command provided - try to find package.json start script
470
+ const packageJsonPath = path.join(process.cwd(), 'package.json');
471
+ if (fs.existsSync(packageJsonPath)) {
472
+ try {
473
+ const pkg = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
474
+ if (pkg.scripts?.start) {
475
+ console.log('\x1b[36mNo command specified, running npm start...\x1b[0m\n');
476
+ userCommand = ['npm', 'start'];
477
+ }
478
+ else if (pkg.scripts?.dev) {
479
+ console.log('\x1b[36mNo command specified, running npm run dev...\x1b[0m\n');
480
+ userCommand = ['npm', 'run', 'dev'];
481
+ }
482
+ else {
483
+ console.error('Error: No command specified and no start/dev script found in package.json');
484
+ console.log('\nUsage: npx monora-ai start -- <command>');
485
+ console.log(' npx monora-ai start -- npm run dev');
486
+ console.log(' npx monora-ai start -- node server.js');
487
+ process.exit(1);
488
+ }
489
+ }
490
+ catch {
491
+ console.error('Error: No command specified');
492
+ process.exit(1);
493
+ }
494
+ }
495
+ else {
496
+ console.error('Error: No command specified');
497
+ console.log('\nUsage: npx monora-ai start -- <command>');
498
+ process.exit(1);
499
+ }
500
+ }
501
+ // Find the register module path
502
+ let registerPath;
503
+ try {
504
+ // Try to find monora-ai/register
505
+ registerPath = require.resolve('monora-ai/register');
506
+ }
507
+ catch {
508
+ // Fall back to local path for development
509
+ registerPath = path.resolve(__dirname, 'register.js');
510
+ if (!fs.existsSync(registerPath)) {
511
+ // Try TypeScript version
512
+ registerPath = path.resolve(__dirname, 'register.ts');
513
+ }
514
+ }
515
+ // Check for config file
516
+ const configPath = fs.existsSync('monora.yml')
517
+ ? 'monora.yml'
518
+ : fs.existsSync('monora.json')
519
+ ? 'monora.json'
520
+ : null;
521
+ // Build environment
522
+ const env = {
523
+ ...process.env,
524
+ MONORA_AUTO_INIT: 'true',
300
525
  };
301
- return config;
526
+ if (configPath) {
527
+ env.MONORA_CONFIG_PATH = configPath;
528
+ }
529
+ // Add register to NODE_OPTIONS
530
+ const existingNodeOptions = process.env.NODE_OPTIONS || '';
531
+ const escapedRegisterPath = registerPath.replace(/"/g, '\\"');
532
+ env.NODE_OPTIONS = `${existingNodeOptions} --require "${escapedRegisterPath}"`.trim();
533
+ console.log('\x1b[36m=== Monora Start ===\x1b[0m\n');
534
+ console.log('Instrumentation: \x1b[32menabled\x1b[0m');
535
+ if (configPath) {
536
+ console.log(`Config: ${configPath}`);
537
+ }
538
+ else {
539
+ console.log('Config: auto-detected');
540
+ }
541
+ console.log(`Running: ${userCommand.join(' ')}\n`);
542
+ console.log('\x1b[90m--- Application Output ---\x1b[0m\n');
543
+ // Spawn the user command
544
+ const child = spawn(userCommand[0], userCommand.slice(1), {
545
+ env,
546
+ stdio: 'inherit',
547
+ shell: true,
548
+ });
549
+ child.on('exit', (code) => {
550
+ process.exit(code ?? 0);
551
+ });
552
+ child.on('error', (err) => {
553
+ console.error(`Failed to start command: ${err.message}`);
554
+ process.exit(1);
555
+ });
302
556
  }
303
- async function runInitWizard(configPath, format, assumeYes, force) {
557
+ async function runInitWizard(configPath, format, assumeYes, force, advanced = false, preset) {
304
558
  if (fs.existsSync(configPath) && !force) {
305
559
  if (assumeYes) {
306
560
  console.error(`${configPath} already exists. Use --force to overwrite.`);
307
561
  process.exit(1);
308
562
  }
309
563
  }
564
+ if (preset) {
565
+ const detectedService = (0, autodetect_1.detectServiceName)() || path.basename(process.cwd()) || 'monora-app';
566
+ const config = (0, init_1.buildPresetConfig)(preset, { serviceName: detectedService });
567
+ const output = renderConfigOutput(config, format);
568
+ fs.writeFileSync(configPath, output, 'utf-8');
569
+ console.log(`\nMonora config written to ${configPath}`);
570
+ console.log(`Preset: ${preset}`);
571
+ console.log('\n=== Next Steps ===\n');
572
+ console.log('Use the generated config file:');
573
+ console.log(` import { init } from 'monora-ai';`);
574
+ console.log(` init({ configPath: '${configPath}' });`);
575
+ console.log('');
576
+ console.log('Generate reports with:');
577
+ console.log(' npx monora-ai report --input ./monora_events.jsonl --output monora_report.json');
578
+ return;
579
+ }
580
+ // Use streamlined wizard by default (unless --advanced)
581
+ if (!advanced) {
582
+ return runStreamlinedWizard(configPath, format, assumeYes);
583
+ }
310
584
  // Auto-detect project info
311
585
  const detectedService = (0, autodetect_1.detectServiceName)() || path.basename(process.cwd()) || 'monora-app';
312
586
  const detectedEnv = (0, autodetect_1.detectEnvironment)();
@@ -324,22 +598,22 @@ async function runInitWizard(configPath, format, assumeYes, force) {
324
598
  }
325
599
  console.log('');
326
600
  // Generate smart defaults based on detection
327
- const smartAllowlist = detectedSdks.includes('openai') && detectedSdks.includes('anthropic')
328
- ? ['gpt-4*', 'gpt-4o*', 'claude-3-*']
329
- : detectedSdks.includes('openai')
330
- ? ['gpt-4*', 'gpt-4o*', 'o1-*']
331
- : detectedSdks.includes('anthropic')
332
- ? ['claude-3-*', 'claude-sonnet-4-*', 'claude-opus-4-*']
333
- : [];
601
+ const smartAllowlist = [...init_1.DEFAULT_ALLOWLIST_PATTERNS];
334
602
  let answers;
335
603
  if (assumeYes) {
336
604
  // Smart defaults for --yes mode
337
605
  answers = {
338
606
  service_name: detectedService,
339
607
  environment: detectedEnv,
340
- stdout_sink: detectedEnv === 'dev',
608
+ stdout_sink: false,
609
+ stdout_format: 'pretty',
341
610
  file_sink: true,
342
- file_path: detectedEnv === 'production' ? './logs/monora_events.jsonl' : './monora_events.jsonl',
611
+ file_path: detectedEnv === 'production'
612
+ ? './logs/monora_events.jsonl'
613
+ : detectedEnv === 'poc'
614
+ ? './monora_poc_events.jsonl'
615
+ : './monora_events.jsonl',
616
+ file_rotation: 'none',
343
617
  https_sink: false,
344
618
  enable_policies: smartAllowlist.length > 0,
345
619
  allowlist: smartAllowlist,
@@ -348,9 +622,30 @@ async function runInitWizard(configPath, format, assumeYes, force) {
348
622
  instrumentation_purpose: 'general',
349
623
  enable_data_handling: false,
350
624
  data_handling_mode: 'redact',
351
- violation_webhook: null,
625
+ violation_webhook: undefined,
352
626
  queue_full_mode: 'warn',
353
- queue_full_timeout_sec: null,
627
+ queue_full_timeout_sec: undefined,
628
+ enable_attribution: false,
629
+ attribution_company: undefined,
630
+ attribution_role: undefined,
631
+ attribution_email: undefined,
632
+ attribution_source: undefined,
633
+ attribution_use_case: undefined,
634
+ attribution_team_size: undefined,
635
+ attribution_business_owner: undefined,
636
+ attribution_data_categories: [],
637
+ telemetry_enabled: false,
638
+ telemetry_send_data: false,
639
+ telemetry_data_residency: undefined,
640
+ enable_audit_metadata: false,
641
+ audit_use_case_name: undefined,
642
+ audit_business_owner: undefined,
643
+ audit_data_categories: [],
644
+ audit_risk_level: 'medium',
645
+ audit_compliance_frameworks: [],
646
+ audit_review_date: undefined,
647
+ audit_reviewer: undefined,
648
+ audit_notes: undefined,
354
649
  };
355
650
  console.log('Using smart defaults based on auto-detection...\n');
356
651
  if (answers.file_sink && answers.file_path) {
@@ -364,23 +659,33 @@ async function runInitWizard(configPath, format, assumeYes, force) {
364
659
  else {
365
660
  const rl = createInterface();
366
661
  try {
662
+ const selectedSinks = await askSinkSelection(rl, ['file']);
663
+ let stdoutSelected = selectedSinks.includes('stdout');
664
+ if (!stdoutSelected) {
665
+ stdoutSelected = await confirm(rl, 'Enable console output?', false);
666
+ }
367
667
  answers = {
368
668
  service_name: await ask(rl, 'Service name', detectedService),
369
- environment: await ask(rl, 'Environment (dev/staging/production)', detectedEnv),
370
- stdout_sink: await confirm(rl, 'Enable stdout sink?', detectedEnv === 'dev'),
371
- file_sink: await confirm(rl, 'Enable file sink?', true),
372
- https_sink: await confirm(rl, 'Enable HTTPS sink?', false),
669
+ environment: await ask(rl, 'Environment (dev/poc/staging/production)', detectedEnv),
670
+ stdout_sink: stdoutSelected,
671
+ stdout_format: 'pretty',
672
+ file_sink: selectedSinks.includes('file'),
673
+ file_rotation: 'none',
674
+ https_sink: selectedSinks.includes('https'),
373
675
  enable_policies: await confirm(rl, 'Configure model allowlist?', smartAllowlist.length > 0),
374
676
  allowlist: [],
375
677
  denylist: [],
376
678
  enable_instrumentation: await confirm(rl, 'Enable auto-instrumentation?', detectedSdks.length > 0),
377
679
  enable_data_handling: await confirm(rl, 'Enable data redaction rules?', false),
378
680
  queue_full_mode: await ask(rl, 'Queue overflow mode (warn/raise/block)', 'warn'),
681
+ enable_attribution: false,
379
682
  };
380
683
  if (answers.file_sink) {
381
684
  const defaultPath = answers.environment === 'production'
382
685
  ? './logs/monora_events.jsonl'
383
- : './monora_events.jsonl';
686
+ : answers.environment === 'poc'
687
+ ? './monora_poc_events.jsonl'
688
+ : './monora_events.jsonl';
384
689
  answers.file_path = await ask(rl, 'File sink path', defaultPath);
385
690
  if (answers.file_path) {
386
691
  const fileCheck = checkFileWritable(answers.file_path);
@@ -419,7 +724,7 @@ async function runInitWizard(configPath, format, assumeYes, force) {
419
724
  if (answers.enable_policies) {
420
725
  const defaultAllowlist = smartAllowlist.length > 0
421
726
  ? smartAllowlist.join(',')
422
- : 'gpt-4*,claude-3-*';
727
+ : init_1.DEFAULT_ALLOWLIST_PATTERNS.join(',');
423
728
  answers.allowlist = parseList(await ask(rl, 'Allowlist patterns (comma-separated)', defaultAllowlist));
424
729
  answers.denylist = parseList(await ask(rl, 'Denylist patterns (comma-separated)', ''));
425
730
  }
@@ -463,7 +768,7 @@ async function runInitWizard(configPath, format, assumeYes, force) {
463
768
  while (true) {
464
769
  const timeout = await ask(rl, 'Queue full timeout (seconds, blank for no timeout)', '');
465
770
  if (!timeout) {
466
- answers.queue_full_timeout_sec = null;
771
+ answers.queue_full_timeout_sec = undefined;
467
772
  break;
468
773
  }
469
774
  const parsed = Number(timeout);
@@ -474,15 +779,54 @@ async function runInitWizard(configPath, format, assumeYes, force) {
474
779
  console.warn('Please enter a valid number or leave blank.');
475
780
  }
476
781
  }
782
+ console.log('\nOptional attribution & compliance metadata:');
783
+ console.log('Shared info helps improve Monora; nothing is sent unless you opt in.\n');
784
+ answers.enable_attribution = await confirm(rl, 'Provide optional project attribution info?', true);
785
+ if (answers.enable_attribution) {
786
+ answers.attribution_company = (await ask(rl, 'Company name (optional)', '')).trim() || null;
787
+ answers.attribution_role = (await ask(rl, 'Role (optional)', '')).trim() || null;
788
+ answers.attribution_email = (await ask(rl, 'Work email (optional)', '')).trim() || null;
789
+ answers.attribution_source = (await ask(rl, 'How did you find Monora? (optional)', '')).trim() || null;
790
+ answers.attribution_use_case = (await ask(rl, 'Use case (optional)', '')).trim() || null;
791
+ answers.attribution_team_size = (await ask(rl, 'Team size (solo/small/medium/large, optional)', '')).trim() || null;
792
+ answers.attribution_business_owner = (await ask(rl, 'Business owner (optional)', '')).trim() || null;
793
+ const categories = (await ask(rl, 'Data categories touched (comma-separated, optional)', '')).trim();
794
+ answers.attribution_data_categories = categories ? parseList(categories) : [];
795
+ }
796
+ answers.telemetry_enabled = await confirm(rl, 'Enable anonymous usage telemetry?', false);
797
+ if (answers.telemetry_enabled) {
798
+ answers.telemetry_send_data = await confirm(rl, 'Allow sending anonymized usage data to Monora?', false);
799
+ if (answers.telemetry_send_data) {
800
+ answers.telemetry_data_residency = (await ask(rl, 'Telemetry data residency (us/eu)', 'us')).trim();
801
+ }
802
+ else {
803
+ answers.telemetry_data_residency = undefined;
804
+ }
805
+ }
806
+ else {
807
+ answers.telemetry_send_data = false;
808
+ answers.telemetry_data_residency = undefined;
809
+ }
810
+ answers.enable_audit_metadata = await confirm(rl, 'Add audit metadata for compliance?', false);
811
+ if (answers.enable_audit_metadata) {
812
+ answers.audit_use_case_name = (await ask(rl, 'Audit use case name (optional)', '')).trim() || null;
813
+ answers.audit_business_owner = (await ask(rl, 'Audit business owner (optional)', '')).trim() || null;
814
+ const auditCategories = (await ask(rl, 'Audit data categories (comma-separated, optional)', '')).trim();
815
+ answers.audit_data_categories = auditCategories ? parseList(auditCategories) : [];
816
+ answers.audit_risk_level = (await ask(rl, 'Audit risk level (low/medium/high/critical)', 'medium')).trim();
817
+ const frameworks = (await ask(rl, 'Compliance frameworks (comma-separated, optional)', '')).trim();
818
+ answers.audit_compliance_frameworks = frameworks ? parseList(frameworks) : [];
819
+ answers.audit_review_date = (await ask(rl, 'Review date (optional)', '')).trim() || null;
820
+ answers.audit_reviewer = (await ask(rl, 'Reviewer (optional)', '')).trim() || null;
821
+ answers.audit_notes = (await ask(rl, 'Notes (optional)', '')).trim() || null;
822
+ }
477
823
  }
478
824
  finally {
479
825
  rl.close();
480
826
  }
481
827
  }
482
- const config = buildConfig(answers);
483
- const output = format === 'json'
484
- ? JSON.stringify(config, null, 2)
485
- : yaml.dump(config, { sortKeys: false, noRefs: true });
828
+ const config = (0, init_1.buildWizardConfig)(answers);
829
+ const output = renderConfigOutput(config, format);
486
830
  fs.writeFileSync(configPath, output, 'utf-8');
487
831
  console.log(`\nMonora config written to ${configPath}`);
488
832
  console.log('\n=== Next Steps ===\n');
@@ -496,6 +840,10 @@ async function runInitWizard(configPath, format, assumeYes, force) {
496
840
  console.log(` import { init } from 'monora-ai';`);
497
841
  console.log(` init({ configPath: '${configPath}' });`);
498
842
  console.log('');
843
+ console.log('Generate reports with:');
844
+ console.log(' npx monora-ai report --input ./monora_events.jsonl --output monora_report.json');
845
+ console.log(' (If rotation is enabled, use ./monora_events.latest.jsonl)');
846
+ console.log('');
499
847
  if (detectedSdks.length > 0) {
500
848
  console.log(`Detected SDKs (${detectedSdks.join(', ')}) will be auto-instrumented.`);
501
849
  }
@@ -503,11 +851,14 @@ async function runInitWizard(configPath, format, assumeYes, force) {
503
851
  function parseInitOptions(args) {
504
852
  const configPath = getFlagValue(args, '--path') || 'monora.yml';
505
853
  const format = getFlagValue(args, '--format') || 'yaml';
854
+ const preset = normalizeInitPreset(getFlagValue(args, '--preset'));
506
855
  return {
507
856
  path: configPath,
508
857
  format: format === 'json' ? 'json' : 'yaml',
509
858
  yes: hasFlag(args, '--yes'),
510
859
  force: hasFlag(args, '--force'),
860
+ advanced: hasFlag(args, '--advanced'),
861
+ preset,
511
862
  };
512
863
  }
513
864
  function parseReportOptions(args) {
@@ -553,6 +904,7 @@ function parseSecurityReviewOptions(args) {
553
904
  };
554
905
  }
555
906
  function parseTrustPackageOptions(args) {
907
+ const target = Number(getFlagValue(args, '--control-coverage-target') || '0.9');
556
908
  return {
557
909
  input: getFlagValue(args, '--input'),
558
910
  traceId: getFlagValue(args, '--trace-id'),
@@ -561,6 +913,17 @@ function parseTrustPackageOptions(args) {
561
913
  sign: getFlagValue(args, '--sign') || undefined,
562
914
  gpgKey: getFlagValue(args, '--gpg-key'),
563
915
  gpgHome: getFlagValue(args, '--gpg-home'),
916
+ evidenceManifest: getFlagValue(args, '--evidence-manifest'),
917
+ evidenceRuntime: hasFlag(args, '--evidence-runtime'),
918
+ evidenceStandard: getFlagValue(args, '--evidence-standard') || undefined,
919
+ evidenceNoLineage: hasFlag(args, '--evidence-no-lineage'),
920
+ evidenceNoHashChain: hasFlag(args, '--evidence-no-hash-chain'),
921
+ evidenceNoWorkflowState: hasFlag(args, '--evidence-no-workflow-state'),
922
+ evidenceNoAimsState: hasFlag(args, '--evidence-no-aims-state'),
923
+ controlCatalog: getFlagValue(args, '--control-catalog'),
924
+ controlWorkflowState: getFlagValue(args, '--control-workflow-state'),
925
+ controlCoverageTarget: Number.isFinite(target) ? target : 0.9,
926
+ controlCoverage: getFlagValue(args, '--control-coverage'),
564
927
  schema: !hasFlag(args, '--no-schema'),
565
928
  verify: !hasFlag(args, '--no-verify'),
566
929
  signatureVerify: !hasFlag(args, '--no-signature-verify'),
@@ -867,7 +1230,7 @@ async function runReport(options) {
867
1230
  verifySignatures(events, config);
868
1231
  }
869
1232
  const policies = config.policies || undefined;
870
- const report = (0, report_1.buildReport)(events, policies);
1233
+ const report = (0, report_1.buildReport)(events, policies, config.registry);
871
1234
  if (options.format === 'markdown') {
872
1235
  (0, report_1.writeMarkdown)(options.output, report);
873
1236
  }
@@ -961,7 +1324,19 @@ async function runTrustPackage(options) {
961
1324
  if (options.signatureVerify) {
962
1325
  verifySignatures(events, config);
963
1326
  }
964
- let trustPackage = (0, trust_package_1.buildTrustPackage)(options.traceId, events, config);
1327
+ let trustPackage = (0, trust_package_1.buildTrustPackage)(options.traceId, events, config, {
1328
+ evidenceManifestPath: options.evidenceManifest,
1329
+ evidenceManifestAuto: options.evidenceRuntime,
1330
+ evidenceManifestStandard: options.evidenceStandard,
1331
+ evidenceManifestIncludeLineage: !options.evidenceNoLineage,
1332
+ evidenceManifestIncludeHashChain: !options.evidenceNoHashChain,
1333
+ evidenceManifestIncludeWorkflowState: !options.evidenceNoWorkflowState,
1334
+ evidenceManifestIncludeAimsState: !options.evidenceNoAimsState,
1335
+ controlCatalogPath: options.controlCatalog,
1336
+ controlWorkflowStatePath: options.controlWorkflowState,
1337
+ controlCoverageTarget: options.controlCoverageTarget,
1338
+ controlCoveragePath: options.controlCoverage,
1339
+ });
965
1340
  if (options.sign) {
966
1341
  if (options.sign !== 'gpg') {
967
1342
  console.error(`Unsupported signing type: ${options.sign}`);
@@ -982,6 +1357,342 @@ async function runTrustPackage(options) {
982
1357
  (0, trust_package_1.writeTrustPackage)(options.output, trustPackage);
983
1358
  console.log(`Trust package generated: ${options.output}`);
984
1359
  }
1360
+ function loadAimsStateIfPresent(statePath) {
1361
+ if (!statePath) {
1362
+ return;
1363
+ }
1364
+ if (!fs.existsSync(statePath)) {
1365
+ return;
1366
+ }
1367
+ (0, aims_governance_1.loadAimsGovernanceState)(statePath, { replaceRuntime: true });
1368
+ }
1369
+ function saveAimsStateIfPresent(statePath) {
1370
+ if (!statePath) {
1371
+ return;
1372
+ }
1373
+ (0, aims_governance_1.exportAimsGovernanceState)(statePath);
1374
+ }
1375
+ function emitAimsJson(payload) {
1376
+ console.log(JSON.stringify(payload, null, 2));
1377
+ }
1378
+ async function runAims(args) {
1379
+ const subcommand = args[0];
1380
+ const subArgs = args.slice(1);
1381
+ if (!subcommand) {
1382
+ usage();
1383
+ process.exit(1);
1384
+ }
1385
+ const statePath = getFlagValue(subArgs, '--state');
1386
+ loadAimsStateIfPresent(statePath);
1387
+ const required = (flag) => {
1388
+ const value = getFlagValue(subArgs, flag);
1389
+ if (!value) {
1390
+ throw new Error(`Missing required flag: ${flag}`);
1391
+ }
1392
+ return value;
1393
+ };
1394
+ if (subcommand === 'summary') {
1395
+ emitAimsJson((0, aims_governance_1.getAimsGovernanceSummary)());
1396
+ return;
1397
+ }
1398
+ if (subcommand === 'export-state') {
1399
+ const outputPath = required('--output');
1400
+ const payload = (0, aims_governance_1.exportAimsGovernanceState)(outputPath);
1401
+ emitAimsJson({ state_type: payload.state_type, output: outputPath });
1402
+ return;
1403
+ }
1404
+ if (subcommand === 'import-state') {
1405
+ const inputPath = required('--input');
1406
+ const payload = (0, aims_governance_1.loadAimsGovernanceState)(inputPath, { replaceRuntime: true });
1407
+ const policyCount = Array.isArray(payload.policies) ? payload.policies.length : 0;
1408
+ const concernCount = Array.isArray(payload.concern_reports) ? payload.concern_reports.length : 0;
1409
+ emitAimsJson({
1410
+ input: inputPath,
1411
+ policies: policyCount,
1412
+ concerns: concernCount,
1413
+ });
1414
+ return;
1415
+ }
1416
+ if (subcommand === 'policy-create') {
1417
+ const policy = (0, aims_governance_1.createPolicyDocument)({
1418
+ policyId: required('--policy-id'),
1419
+ title: required('--title'),
1420
+ owner: required('--owner'),
1421
+ reviewFrequencyDays: Number(getFlagValue(subArgs, '--review-frequency-days') || '365'),
1422
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1423
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1424
+ });
1425
+ saveAimsStateIfPresent(statePath);
1426
+ emitAimsJson(policy);
1427
+ return;
1428
+ }
1429
+ if (subcommand === 'policy-add-version') {
1430
+ const version = (0, aims_governance_1.addPolicyVersion)({
1431
+ policyId: required('--policy-id'),
1432
+ changeSummary: required('--change-summary'),
1433
+ createdBy: required('--created-by'),
1434
+ content: getFlagValue(subArgs, '--content'),
1435
+ artifactPath: getFlagValue(subArgs, '--artifact-path'),
1436
+ requiredReviewers: parseOptionalList(getFlagValue(subArgs, '--required-reviewers')),
1437
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1438
+ });
1439
+ saveAimsStateIfPresent(statePath);
1440
+ emitAimsJson(version);
1441
+ return;
1442
+ }
1443
+ if (subcommand === 'policy-submit') {
1444
+ const version = (0, aims_governance_1.submitPolicyVersion)({
1445
+ policyId: required('--policy-id'),
1446
+ versionId: required('--version-id'),
1447
+ submittedBy: required('--submitted-by'),
1448
+ reviewerChain: parseOptionalList(getFlagValue(subArgs, '--reviewer-chain')),
1449
+ note: getFlagValue(subArgs, '--note'),
1450
+ });
1451
+ saveAimsStateIfPresent(statePath);
1452
+ emitAimsJson(version);
1453
+ return;
1454
+ }
1455
+ if (subcommand === 'policy-approve') {
1456
+ const version = (0, aims_governance_1.approvePolicyVersion)({
1457
+ policyId: required('--policy-id'),
1458
+ versionId: required('--version-id'),
1459
+ approver: required('--approver'),
1460
+ note: getFlagValue(subArgs, '--note'),
1461
+ force: hasFlag(subArgs, '--force'),
1462
+ });
1463
+ saveAimsStateIfPresent(statePath);
1464
+ emitAimsJson(version);
1465
+ return;
1466
+ }
1467
+ if (subcommand === 'policy-reject') {
1468
+ const version = (0, aims_governance_1.rejectPolicyVersion)({
1469
+ policyId: required('--policy-id'),
1470
+ versionId: required('--version-id'),
1471
+ reviewer: required('--reviewer'),
1472
+ note: required('--note'),
1473
+ });
1474
+ saveAimsStateIfPresent(statePath);
1475
+ emitAimsJson(version);
1476
+ return;
1477
+ }
1478
+ if (subcommand === 'policy-review') {
1479
+ const version = (0, aims_governance_1.recordPolicyReview)({
1480
+ policyId: required('--policy-id'),
1481
+ versionId: required('--version-id'),
1482
+ reviewer: required('--reviewer'),
1483
+ summary: required('--summary'),
1484
+ outcome: getFlagValue(subArgs, '--outcome') || 'accepted',
1485
+ });
1486
+ saveAimsStateIfPresent(statePath);
1487
+ emitAimsJson(version);
1488
+ return;
1489
+ }
1490
+ if (subcommand === 'policy-list') {
1491
+ emitAimsJson((0, aims_governance_1.listPolicyDocuments)());
1492
+ return;
1493
+ }
1494
+ if (subcommand === 'policy-get') {
1495
+ const policy = (0, aims_governance_1.getPolicyDocument)(required('--policy-id'));
1496
+ if (!policy) {
1497
+ throw new Error(`Policy not found: ${required('--policy-id')}`);
1498
+ }
1499
+ emitAimsJson(policy);
1500
+ return;
1501
+ }
1502
+ if (subcommand === 'policy-workflows') {
1503
+ const policyId = getFlagValue(subArgs, '--policy-id');
1504
+ const buildStatus = (policy) => {
1505
+ const workflowMap = { ...(policy.workflow_ids || {}) };
1506
+ if (Object.keys(workflowMap).length === 0) {
1507
+ const workflows = (0, control_backbone_1.listWorkflowTasks)({}).filter((workflow) => workflow.metadata?.policy_id === policy.policy_id);
1508
+ for (const workflow of workflows) {
1509
+ workflowMap[workflow.control_id] = workflow.workflow_id;
1510
+ }
1511
+ }
1512
+ const entries = Object.entries(workflowMap).sort(([a], [b]) => a.localeCompare(b)).map(([controlId, workflowId]) => {
1513
+ const workflow = (0, control_backbone_1.getWorkflowTask)(workflowId);
1514
+ if (!workflow) {
1515
+ return { control_id: controlId, workflow_id: workflowId, status: 'missing' };
1516
+ }
1517
+ return {
1518
+ control_id: controlId,
1519
+ workflow_id: workflow.workflow_id,
1520
+ status: workflow.status,
1521
+ owner: workflow.owner,
1522
+ due_at: workflow.due_at,
1523
+ updated_at: workflow.updated_at,
1524
+ };
1525
+ });
1526
+ return {
1527
+ policy_id: policy.policy_id,
1528
+ title: policy.title,
1529
+ owner: policy.owner,
1530
+ active_version_id: policy.active_version_id,
1531
+ workflows: entries,
1532
+ };
1533
+ };
1534
+ if (policyId) {
1535
+ const policy = (0, aims_governance_1.getPolicyDocument)(policyId);
1536
+ if (!policy) {
1537
+ throw new Error(`Policy not found: ${policyId}`);
1538
+ }
1539
+ emitAimsJson(buildStatus(policy));
1540
+ return;
1541
+ }
1542
+ emitAimsJson((0, aims_governance_1.listPolicyDocuments)().map((policy) => buildStatus(policy)));
1543
+ return;
1544
+ }
1545
+ if (subcommand === 'policy-approvals') {
1546
+ const policyId = getFlagValue(subArgs, '--policy-id');
1547
+ const versionId = getFlagValue(subArgs, '--version-id');
1548
+ if (versionId && !policyId) {
1549
+ throw new Error('--version-id requires --policy-id');
1550
+ }
1551
+ const policies = policyId ? [(0, aims_governance_1.getPolicyDocument)(policyId)] : (0, aims_governance_1.listPolicyDocuments)();
1552
+ const payload = policies.map((policy) => {
1553
+ if (!policy) {
1554
+ throw new Error(`Policy not found: ${policyId}`);
1555
+ }
1556
+ const versions = (policy.versions || [])
1557
+ .filter((version) => !versionId || version.version_id === versionId)
1558
+ .map((version) => ({
1559
+ version_id: version.version_id,
1560
+ version_number: version.version_number,
1561
+ status: version.status,
1562
+ submitted_at: version.submitted_at,
1563
+ approved_at: version.approved_at,
1564
+ approved_by: version.approved_by,
1565
+ required_reviewers: version.required_reviewers,
1566
+ approvals: version.approvals,
1567
+ review_history: version.review_history,
1568
+ }));
1569
+ return {
1570
+ policy_id: policy.policy_id,
1571
+ title: policy.title,
1572
+ owner: policy.owner,
1573
+ active_version_id: policy.active_version_id,
1574
+ versions,
1575
+ };
1576
+ });
1577
+ emitAimsJson(payload);
1578
+ return;
1579
+ }
1580
+ if (subcommand === 'policy-due') {
1581
+ emitAimsJson((0, aims_governance_1.getDuePolicyReviews)({
1582
+ referenceTime: getFlagValue(subArgs, '--reference-time'),
1583
+ }));
1584
+ return;
1585
+ }
1586
+ if (subcommand === 'context-record') {
1587
+ const record = (0, aims_governance_1.recordAimsContext)({
1588
+ scope: required('--scope'),
1589
+ approvedBy: required('--approved-by'),
1590
+ interestedParties: parseOptionalList(getFlagValue(subArgs, '--interested-parties')),
1591
+ internalIssues: parseOptionalList(getFlagValue(subArgs, '--internal-issues')),
1592
+ externalIssues: parseOptionalList(getFlagValue(subArgs, '--external-issues')),
1593
+ objectives: parseOptionalList(getFlagValue(subArgs, '--objectives')),
1594
+ reviewFrequencyDays: Number(getFlagValue(subArgs, '--review-frequency-days') || '365'),
1595
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1596
+ });
1597
+ saveAimsStateIfPresent(statePath);
1598
+ emitAimsJson(record);
1599
+ return;
1600
+ }
1601
+ if (subcommand === 'context-get') {
1602
+ emitAimsJson((0, aims_governance_1.getAimsContext)() || {});
1603
+ return;
1604
+ }
1605
+ if (subcommand === 'raci-register') {
1606
+ const entry = (0, aims_governance_1.registerRaciEntry)({
1607
+ functionName: required('--function-name'),
1608
+ owner: required('--owner'),
1609
+ accountable: parseOptionalList(required('--accountable')),
1610
+ responsible: parseOptionalList(required('--responsible')),
1611
+ consulted: parseOptionalList(getFlagValue(subArgs, '--consulted')),
1612
+ informed: parseOptionalList(getFlagValue(subArgs, '--informed')),
1613
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1614
+ notes: getFlagValue(subArgs, '--notes'),
1615
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1616
+ });
1617
+ saveAimsStateIfPresent(statePath);
1618
+ emitAimsJson(entry);
1619
+ return;
1620
+ }
1621
+ if (subcommand === 'raci-list') {
1622
+ emitAimsJson((0, aims_governance_1.listRaciEntries)());
1623
+ return;
1624
+ }
1625
+ if (subcommand === 'training-record') {
1626
+ const record = (0, aims_governance_1.recordGovernanceTraining)({
1627
+ userId: required('--user-id'),
1628
+ topic: required('--topic'),
1629
+ recordedBy: required('--recorded-by'),
1630
+ completedAt: getFlagValue(subArgs, '--completed-at'),
1631
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1632
+ notes: getFlagValue(subArgs, '--notes'),
1633
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1634
+ });
1635
+ saveAimsStateIfPresent(statePath);
1636
+ emitAimsJson(record);
1637
+ return;
1638
+ }
1639
+ if (subcommand === 'training-list') {
1640
+ emitAimsJson((0, aims_governance_1.listGovernanceTrainingRecords)());
1641
+ return;
1642
+ }
1643
+ if (subcommand === 'concern-file') {
1644
+ const report = (0, aims_governance_1.fileConcernReport)({
1645
+ title: required('--title'),
1646
+ description: required('--description'),
1647
+ reportedBy: required('--reported-by'),
1648
+ severity: getFlagValue(subArgs, '--severity') || 'medium',
1649
+ assignedTo: getFlagValue(subArgs, '--assigned-to'),
1650
+ controlIds: parseOptionalList(getFlagValue(subArgs, '--control-ids')),
1651
+ tags: parseOptionalList(getFlagValue(subArgs, '--tags')),
1652
+ metadata: parseJsonObject(getFlagValue(subArgs, '--metadata')),
1653
+ });
1654
+ saveAimsStateIfPresent(statePath);
1655
+ emitAimsJson(report);
1656
+ return;
1657
+ }
1658
+ if (subcommand === 'concern-update') {
1659
+ const report = (0, aims_governance_1.updateConcernReport)({
1660
+ concernId: required('--concern-id'),
1661
+ actor: required('--actor'),
1662
+ status: required('--status'),
1663
+ note: getFlagValue(subArgs, '--note'),
1664
+ assignedTo: getFlagValue(subArgs, '--assigned-to'),
1665
+ });
1666
+ saveAimsStateIfPresent(statePath);
1667
+ emitAimsJson(report);
1668
+ return;
1669
+ }
1670
+ if (subcommand === 'concern-resolve') {
1671
+ const report = (0, aims_governance_1.resolveConcernReport)({
1672
+ concernId: required('--concern-id'),
1673
+ resolvedBy: required('--resolved-by'),
1674
+ resolutionSummary: required('--resolution-summary'),
1675
+ close: !hasFlag(subArgs, '--no-close'),
1676
+ });
1677
+ saveAimsStateIfPresent(statePath);
1678
+ emitAimsJson(report);
1679
+ return;
1680
+ }
1681
+ if (subcommand === 'concern-list') {
1682
+ const status = getFlagValue(subArgs, '--status');
1683
+ emitAimsJson((0, aims_governance_1.listConcernReports)({ status: status }));
1684
+ return;
1685
+ }
1686
+ if (subcommand === 'concern-get') {
1687
+ const report = (0, aims_governance_1.getConcernReport)(required('--concern-id'));
1688
+ if (!report) {
1689
+ throw new Error(`Concern not found: ${required('--concern-id')}`);
1690
+ }
1691
+ emitAimsJson(report);
1692
+ return;
1693
+ }
1694
+ throw new Error(`Unsupported aims subcommand: ${subcommand}`);
1695
+ }
985
1696
  async function runVerify(options) {
986
1697
  if (!options.input) {
987
1698
  usage();
@@ -1086,9 +1797,12 @@ async function runVerify(options) {
1086
1797
  async function runValidate(args) {
1087
1798
  const configPath = getFlagValue(args, '--config') || 'monora.yml';
1088
1799
  const asJson = hasFlag(args, '--json');
1800
+ const modeArg = normalizeValidationMode(getFlagValue(args, '--mode'));
1089
1801
  try {
1090
1802
  const config = (0, config_1.loadConfig)({ configPath });
1091
- const results = (0, diagnostics_1.validateConfig)(config);
1803
+ const env = config.defaults?.environment || 'dev';
1804
+ const mode = modeArg || (env === 'production' ? 'strict' : 'lenient');
1805
+ const results = (0, diagnostics_1.validateConfig)(config, { mode });
1092
1806
  const exitCode = (0, diagnostics_1.emitResults)(results, { json: asJson });
1093
1807
  process.exit(exitCode);
1094
1808
  }
@@ -1102,9 +1816,8 @@ async function runDoctor(args) {
1102
1816
  const asJson = hasFlag(args, '--json');
1103
1817
  const noNetwork = hasFlag(args, '--no-network');
1104
1818
  try {
1105
- const config = (0, config_1.loadConfig)({ configPath });
1106
- const results = (0, diagnostics_1.doctorChecks)(config, { checkNetwork: !noNetwork });
1107
- const exitCode = (0, diagnostics_1.emitResults)(results, { json: asJson });
1819
+ const results = await (0, doctor_1.doctorChecks)(configPath, { checkNetwork: !noNetwork });
1820
+ const exitCode = (0, doctor_1.emitDoctorResults)(results, { json: asJson });
1108
1821
  process.exit(exitCode);
1109
1822
  }
1110
1823
  catch (error) {
@@ -1112,6 +1825,49 @@ async function runDoctor(args) {
1112
1825
  process.exit(1);
1113
1826
  }
1114
1827
  }
1828
+ async function runConfigFix(args) {
1829
+ const configPath = getFlagValue(args, '--config') || 'monora.yml';
1830
+ const dryRun = hasFlag(args, '--dry-run');
1831
+ const noNetwork = hasFlag(args, '--no-network');
1832
+ try {
1833
+ const result = await (0, fix_1.fixConfigFile)(configPath, {
1834
+ dryRun,
1835
+ checkNetwork: !noNetwork,
1836
+ });
1837
+ if (!result.ok) {
1838
+ for (const error of result.errors) {
1839
+ console.error(`Error: ${error}`);
1840
+ }
1841
+ process.exit(1);
1842
+ }
1843
+ if (result.changes.length === 0) {
1844
+ console.log('No fixes required.');
1845
+ return;
1846
+ }
1847
+ console.log('Applied fixes:');
1848
+ for (const change of result.changes) {
1849
+ console.log(` - ${change}`);
1850
+ }
1851
+ if (result.warnings.length > 0) {
1852
+ console.log('Warnings:');
1853
+ for (const warning of result.warnings) {
1854
+ console.log(` - ${warning}`);
1855
+ }
1856
+ }
1857
+ if (dryRun) {
1858
+ console.log('\nDry run only (no files written).');
1859
+ return;
1860
+ }
1861
+ if (result.backupPath) {
1862
+ console.log(`Backup written to ${result.backupPath}`);
1863
+ }
1864
+ console.log(`Updated config saved to ${configPath}`);
1865
+ }
1866
+ catch (error) {
1867
+ console.error(`Error: ${error?.message || error}`);
1868
+ process.exit(1);
1869
+ }
1870
+ }
1115
1871
  async function runCompatReport(args) {
1116
1872
  const baselinePath = getFlagValue(args, '--baseline');
1117
1873
  const outputPath = getFlagValue(args, '--output');
@@ -1333,7 +2089,7 @@ async function runStandardsExcerpt(args) {
1333
2089
  process.exit(1);
1334
2090
  }
1335
2091
  try {
1336
- const payload = (0, standards_ingest_1.applyExcerpts)({ ingestPath, claimsPath, excerptsPath });
2092
+ const payload = await (0, standards_ingest_1.applyExcerpts)({ ingestPath, claimsPath, excerptsPath });
1337
2093
  const output = JSON.stringify(payload, null, pretty ? 2 : undefined);
1338
2094
  if (outputPath) {
1339
2095
  fs.writeFileSync(outputPath, output, 'utf-8');
@@ -1445,7 +2201,7 @@ async function runStandardsReview(args) {
1445
2201
  rl.close();
1446
2202
  }
1447
2203
  try {
1448
- const updated = (0, standards_ingest_1.applyExcerptSelections)({
2204
+ const updated = await (0, standards_ingest_1.applyExcerptSelections)({
1449
2205
  ingestPath,
1450
2206
  claimsPath,
1451
2207
  selections,
@@ -1494,6 +2250,415 @@ async function runStandardsCheck(args) {
1494
2250
  process.exit(1);
1495
2251
  }
1496
2252
  }
2253
+ function normalizeComplianceTargets(values) {
2254
+ const normalized = values
2255
+ .map((value) => value.trim().toLowerCase().replace(/-/g, '_'))
2256
+ .filter(Boolean);
2257
+ const invalid = normalized.filter((value) => !(0, complianceTargets_1.isFrameworkSupported)(value));
2258
+ if (invalid.length > 0) {
2259
+ throw new Error(`Unsupported compliance target(s): ${invalid.join(', ')}`);
2260
+ }
2261
+ return normalized;
2262
+ }
2263
+ async function runSchema(args) {
2264
+ const subcommand = args[0];
2265
+ const subArgs = args.slice(1);
2266
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
2267
+ console.log('Usage: npx monora-ai schema infer [options]');
2268
+ 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>]');
2269
+ process.exit(1);
2270
+ }
2271
+ if (subcommand !== 'infer') {
2272
+ console.error(`Unknown schema subcommand: ${subcommand}`);
2273
+ process.exit(1);
2274
+ }
2275
+ const inputPath = getFlagValue(subArgs, '--input');
2276
+ const outputPath = getFlagValue(subArgs, '--output');
2277
+ const modelName = getFlagValue(subArgs, '--model-name');
2278
+ const modelVersion = getFlagValue(subArgs, '--model-version') || '1.0.0';
2279
+ const sampleSizeRaw = getFlagValue(subArgs, '--sample-size');
2280
+ const sampleSize = sampleSizeRaw ? Number(sampleSizeRaw) : 100;
2281
+ const noPii = hasFlag(subArgs, '--no-pii');
2282
+ const reportPath = getFlagValue(subArgs, '--report');
2283
+ const contractPath = getFlagValue(subArgs, '--contract');
2284
+ if (!inputPath || !outputPath) {
2285
+ console.error('Error: --input and --output are required for schema infer.');
2286
+ process.exit(1);
2287
+ }
2288
+ if (!Number.isFinite(sampleSize) || sampleSize <= 0) {
2289
+ console.error('Error: --sample-size must be > 0.');
2290
+ process.exit(1);
2291
+ }
2292
+ let complianceTargets = [];
2293
+ try {
2294
+ complianceTargets = normalizeComplianceTargets(getFlagValues(subArgs, '--compliance-target'));
2295
+ }
2296
+ catch (error) {
2297
+ console.error(`Error: ${error?.message || error}`);
2298
+ process.exit(1);
2299
+ }
2300
+ try {
2301
+ const spec = (0, schemaInference_1.inferSchemaFromFile)(inputPath, {
2302
+ modelName: modelName || undefined,
2303
+ modelVersion,
2304
+ complianceTargets,
2305
+ detectPii: !noPii,
2306
+ sampleSize,
2307
+ });
2308
+ const outputResolved = path.resolve(outputPath);
2309
+ fs.mkdirSync(path.dirname(outputResolved), { recursive: true });
2310
+ fs.writeFileSync(outputResolved, JSON.stringify((0, spec_1.specToDict)(spec), null, 2), 'utf-8');
2311
+ console.log(`Wrote inferred schema spec to ${outputPath}`);
2312
+ if (contractPath) {
2313
+ const contractResolved = path.resolve(contractPath);
2314
+ fs.mkdirSync(path.dirname(contractResolved), { recursive: true });
2315
+ fs.writeFileSync(contractResolved, JSON.stringify((0, spec_1.specToSchemaContract)(spec), null, 2), 'utf-8');
2316
+ console.log(`Wrote schema contract to ${contractPath}`);
2317
+ }
2318
+ if (reportPath) {
2319
+ const reportResolved = path.resolve(reportPath);
2320
+ fs.mkdirSync(path.dirname(reportResolved), { recursive: true });
2321
+ const events = (0, schemaInference_1.loadEventsFromFile)(inputPath);
2322
+ const report = (0, schemaInference_1.generateInferenceReport)(events, sampleSize);
2323
+ fs.writeFileSync(reportResolved, JSON.stringify(report, null, 2), 'utf-8');
2324
+ console.log(`Wrote inference report to ${reportPath}`);
2325
+ }
2326
+ }
2327
+ catch (error) {
2328
+ console.error(`Error: ${error?.message || error}`);
2329
+ process.exit(1);
2330
+ }
2331
+ }
2332
+ async function runModel(args) {
2333
+ const subcommand = args[0];
2334
+ const subArgs = args.slice(1);
2335
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
2336
+ console.log('Usage: npx monora-ai model create [options]');
2337
+ 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>]');
2338
+ process.exit(1);
2339
+ }
2340
+ if (subcommand !== 'create') {
2341
+ console.error(`Unknown model subcommand: ${subcommand}`);
2342
+ process.exit(1);
2343
+ }
2344
+ const inputPath = getFlagValue(subArgs, '--input');
2345
+ const outputPath = getFlagValue(subArgs, '--output');
2346
+ const modelName = getFlagValue(subArgs, '--model-name') || 'unnamed-model';
2347
+ const modelVersion = getFlagValue(subArgs, '--model-version') || '1.0.0';
2348
+ const riskCategory = getFlagValue(subArgs, '--risk-category') || 'limited';
2349
+ const intendedUse = getFlagValue(subArgs, '--intended-use');
2350
+ const owner = getFlagValue(subArgs, '--owner');
2351
+ const sampleSizeRaw = getFlagValue(subArgs, '--sample-size');
2352
+ const sampleSize = sampleSizeRaw ? Number(sampleSizeRaw) : 100;
2353
+ const noPii = hasFlag(subArgs, '--no-pii');
2354
+ const configOut = getFlagValue(subArgs, '--config-out');
2355
+ const configFormat = (getFlagValue(subArgs, '--config-format') || 'yaml').toLowerCase();
2356
+ const contractOut = getFlagValue(subArgs, '--contract-out');
2357
+ if (!inputPath || !outputPath) {
2358
+ console.error('Error: --input and --output are required for model create.');
2359
+ process.exit(1);
2360
+ }
2361
+ if (!Number.isFinite(sampleSize) || sampleSize <= 0) {
2362
+ console.error('Error: --sample-size must be > 0.');
2363
+ process.exit(1);
2364
+ }
2365
+ if (!['minimal', 'limited', 'high', 'unacceptable'].includes(riskCategory)) {
2366
+ console.error("Error: --risk-category must be one of minimal|limited|high|unacceptable.");
2367
+ process.exit(1);
2368
+ }
2369
+ if (!['yaml', 'json'].includes(configFormat)) {
2370
+ console.error("Error: --config-format must be one of yaml|json.");
2371
+ process.exit(1);
2372
+ }
2373
+ let complianceTargets = [];
2374
+ let tags = [];
2375
+ try {
2376
+ complianceTargets = normalizeComplianceTargets(getFlagValues(subArgs, '--compliance-target'));
2377
+ tags = getFlagValues(subArgs, '--tag');
2378
+ }
2379
+ catch (error) {
2380
+ console.error(`Error: ${error?.message || error}`);
2381
+ process.exit(1);
2382
+ }
2383
+ try {
2384
+ const model = (0, model_1.modelFromData)({
2385
+ source: inputPath,
2386
+ modelName,
2387
+ modelVersion,
2388
+ complianceTargets,
2389
+ riskCategory: riskCategory,
2390
+ intendedUse: intendedUse || undefined,
2391
+ owner: owner || undefined,
2392
+ tags,
2393
+ detectPii: !noPii,
2394
+ sampleSize,
2395
+ });
2396
+ (0, model_1.saveModel)(model, outputPath);
2397
+ console.log(`Wrote model to ${outputPath}`);
2398
+ if (configOut) {
2399
+ (0, model_1.saveConfig)(model, configOut, configFormat);
2400
+ console.log(`Wrote generated config to ${configOut}`);
2401
+ }
2402
+ if (contractOut) {
2403
+ (0, model_1.saveSchemaContract)(model, contractOut);
2404
+ console.log(`Wrote schema contract to ${contractOut}`);
2405
+ }
2406
+ }
2407
+ catch (error) {
2408
+ console.error(`Error: ${error?.message || error}`);
2409
+ process.exit(1);
2410
+ }
2411
+ }
2412
+ async function runOnboard(args) {
2413
+ const subcommand = args[0];
2414
+ const subArgs = args.slice(1);
2415
+ if (!subcommand || subcommand === '--help' || subcommand === '-h') {
2416
+ console.log('Usage: npx monora-ai onboard <init|validate|complete|status> [options]');
2417
+ console.log(' init [--config monora.yml] [--yes] [--force]');
2418
+ console.log(' validate [--config monora.yml] [--input events.jsonl] [--output result.json] [--pretty]');
2419
+ console.log(' complete [--config monora.yml] [--completed-by name] [--output result.json] [--pretty]');
2420
+ console.log(' status [--config monora.yml] [--pretty]');
2421
+ process.exit(1);
2422
+ }
2423
+ if (subcommand === 'init') {
2424
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2425
+ const acceptDefaults = hasFlag(subArgs, '--yes');
2426
+ const force = hasFlag(subArgs, '--force');
2427
+ if (fs.existsSync(configPath) && !force) {
2428
+ if (acceptDefaults) {
2429
+ console.error(`${configPath} already exists. Use --force to overwrite.`);
2430
+ process.exit(1);
2431
+ }
2432
+ const rl = createInterface();
2433
+ const overwrite = await confirm(rl, `${configPath} already exists. Overwrite?`, false);
2434
+ rl.close();
2435
+ if (!overwrite) {
2436
+ console.error('Aborted.');
2437
+ process.exit(1);
2438
+ }
2439
+ }
2440
+ const config = (0, config_1.loadConfig)({ configPath });
2441
+ const onboardingDefaults = (config.onboarding || {});
2442
+ let onboardingEnabled = true;
2443
+ let requiredInProd = true;
2444
+ let logsPath = String(onboardingDefaults?.artifacts?.production_logs_path || './monora_events.jsonl');
2445
+ let schemaPath = String(onboardingDefaults?.artifacts?.schema_contract_path || './onboarding/schema_contract.json');
2446
+ let datasetSamplePath = null;
2447
+ let baselineReportsDir = String(onboardingDefaults?.artifacts?.baseline_reports_dir || './monora_reports/onboarding');
2448
+ let standards = ['SOC2', 'GDPR', 'ISO27001'];
2449
+ let bundles = ['core_observability', 'soc2_access', 'gdpr_privacy', 'iso27001_security'];
2450
+ let toggles = {
2451
+ identity_tracking: true,
2452
+ risk_tracking: true,
2453
+ bias_tracking: false,
2454
+ oversight_tracking: true,
2455
+ data_governance_tracking: true,
2456
+ lifecycle_tracking: true,
2457
+ };
2458
+ let roles = {
2459
+ inputs: ['body.prompt'],
2460
+ outputs: ['body.response'],
2461
+ metadata: ['event_type', 'service_name', 'timestamp'],
2462
+ identifiers: ['event_id', 'trace_id', 'span_id'],
2463
+ };
2464
+ if (!acceptDefaults) {
2465
+ const rl = createInterface();
2466
+ try {
2467
+ onboardingEnabled = await confirm(rl, 'Enable onboarding?', true);
2468
+ requiredInProd = await confirm(rl, 'Require completed onboarding in production?', true);
2469
+ logsPath = await ask(rl, 'Production logs path', logsPath);
2470
+ schemaPath = await ask(rl, 'Schema contract path', schemaPath);
2471
+ const datasetRaw = (await ask(rl, 'Dataset sample path (optional)', '')).trim();
2472
+ datasetSamplePath = datasetRaw || null;
2473
+ baselineReportsDir = await ask(rl, 'Baseline reports output directory', baselineReportsDir);
2474
+ standards = parseOptionalList(await ask(rl, 'Standards (comma-separated)', 'SOC2,GDPR,ISO27001'));
2475
+ if (standards.length === 0) {
2476
+ standards = ['SOC2', 'GDPR', 'ISO27001'];
2477
+ }
2478
+ bundles = parseOptionalList(await ask(rl, 'Enrichment bundles (comma-separated)', 'core_observability,soc2_access,gdpr_privacy,iso27001_security'));
2479
+ if (bundles.length === 0) {
2480
+ bundles = ['core_observability', 'soc2_access', 'gdpr_privacy', 'iso27001_security'];
2481
+ }
2482
+ toggles = {
2483
+ identity_tracking: await confirm(rl, 'Enable identity tracking?', true),
2484
+ risk_tracking: await confirm(rl, 'Enable risk tracking?', true),
2485
+ bias_tracking: await confirm(rl, 'Enable bias tracking?', false),
2486
+ oversight_tracking: await confirm(rl, 'Enable oversight tracking?', true),
2487
+ data_governance_tracking: await confirm(rl, 'Enable data governance tracking?', true),
2488
+ lifecycle_tracking: await confirm(rl, 'Enable lifecycle tracking?', true),
2489
+ };
2490
+ const inputs = parseOptionalList(await ask(rl, 'Model spec input fields (comma-separated)', 'body.prompt'));
2491
+ const outputs = parseOptionalList(await ask(rl, 'Model spec output fields (comma-separated)', 'body.response'));
2492
+ const metadata = parseOptionalList(await ask(rl, 'Model spec metadata fields (comma-separated)', 'event_type,service_name,timestamp'));
2493
+ const identifiers = parseOptionalList(await ask(rl, 'Model spec identifiers (comma-separated)', 'event_id,trace_id,span_id'));
2494
+ roles = {
2495
+ inputs: inputs.length > 0 ? inputs : ['body.prompt'],
2496
+ outputs: outputs.length > 0 ? outputs : ['body.response'],
2497
+ metadata: metadata.length > 0 ? metadata : ['event_type', 'service_name', 'timestamp'],
2498
+ identifiers: identifiers.length > 0 ? identifiers : ['event_id', 'trace_id', 'span_id'],
2499
+ };
2500
+ }
2501
+ finally {
2502
+ rl.close();
2503
+ }
2504
+ }
2505
+ else {
2506
+ const enrichmentsDefaults = (config.enrichments || {});
2507
+ const bundlesDefault = Array.isArray(enrichmentsDefaults.bundles)
2508
+ ? enrichmentsDefaults.bundles
2509
+ : bundles;
2510
+ bundles = bundlesDefault.map((value) => String(value).trim()).filter(Boolean);
2511
+ if (bundles.length === 0) {
2512
+ bundles = ['core_observability', 'soc2_access', 'gdpr_privacy', 'iso27001_security'];
2513
+ }
2514
+ const toggleDefaults = enrichmentsDefaults.toggles && typeof enrichmentsDefaults.toggles === 'object'
2515
+ ? enrichmentsDefaults.toggles
2516
+ : {};
2517
+ toggles = {
2518
+ identity_tracking: Boolean(toggleDefaults.identity_tracking ?? toggles.identity_tracking),
2519
+ risk_tracking: Boolean(toggleDefaults.risk_tracking ?? toggles.risk_tracking),
2520
+ bias_tracking: Boolean(toggleDefaults.bias_tracking ?? toggles.bias_tracking),
2521
+ oversight_tracking: Boolean(toggleDefaults.oversight_tracking ?? toggles.oversight_tracking),
2522
+ data_governance_tracking: Boolean(toggleDefaults.data_governance_tracking ?? toggles.data_governance_tracking),
2523
+ lifecycle_tracking: Boolean(toggleDefaults.lifecycle_tracking ?? toggles.lifecycle_tracking),
2524
+ };
2525
+ }
2526
+ config.onboarding = {
2527
+ enabled: onboardingEnabled,
2528
+ required_in_production: requiredInProd,
2529
+ status: 'draft',
2530
+ standards,
2531
+ artifacts: {
2532
+ production_logs_path: logsPath,
2533
+ schema_contract_path: schemaPath,
2534
+ dataset_sample_path: datasetSamplePath,
2535
+ baseline_reports_dir: baselineReportsDir,
2536
+ },
2537
+ validation: {
2538
+ min_log_records: 100,
2539
+ required_field_presence_threshold: 0.95,
2540
+ type_conformance_threshold: 0.90,
2541
+ },
2542
+ completion: {
2543
+ completed_at: null,
2544
+ completed_by: null,
2545
+ last_validated_at: null,
2546
+ },
2547
+ };
2548
+ config.model_spec = (0, onboarding_1.buildModelSpec)({
2549
+ schemaRef: schemaPath,
2550
+ roles,
2551
+ });
2552
+ config.enrichments = {
2553
+ profile: 'recommended',
2554
+ bundles,
2555
+ toggles,
2556
+ };
2557
+ const enrichmentPlan = (0, onboarding_1.resolveEnrichmentPlan)(config, { apply: true });
2558
+ const ext = path.extname(configPath).toLowerCase();
2559
+ const raw = ext === '.json'
2560
+ ? JSON.stringify(config, null, 2)
2561
+ : yaml.dump(config, { sortKeys: false });
2562
+ fs.writeFileSync(configPath, raw, 'utf-8');
2563
+ const configDir = path.dirname(path.resolve(configPath));
2564
+ const schemaAbs = path.resolve(configDir, schemaPath);
2565
+ fs.mkdirSync(path.dirname(schemaAbs), { recursive: true });
2566
+ if (!fs.existsSync(schemaAbs)) {
2567
+ const schemaTemplate = {
2568
+ schema: {
2569
+ type: 'object',
2570
+ properties: {
2571
+ body: {
2572
+ type: 'object',
2573
+ properties: {
2574
+ prompt: { type: 'string' },
2575
+ response: { type: 'string' },
2576
+ },
2577
+ },
2578
+ },
2579
+ },
2580
+ roles,
2581
+ };
2582
+ fs.writeFileSync(schemaAbs, JSON.stringify(schemaTemplate, null, 2), 'utf-8');
2583
+ }
2584
+ try {
2585
+ const state = (0, runtime_1.getState)();
2586
+ if (state && typeof state.emitInternal === 'function') {
2587
+ state.emitInternal({
2588
+ event_type: 'onboarding_started',
2589
+ body: {
2590
+ config_path: configPath,
2591
+ standards,
2592
+ schema_contract_path: schemaPath,
2593
+ bundles,
2594
+ },
2595
+ purpose: 'governance',
2596
+ });
2597
+ }
2598
+ }
2599
+ catch {
2600
+ // no-op
2601
+ }
2602
+ console.log(`Onboarding config initialized in ${configPath}`);
2603
+ console.log(`Schema contract template: ${schemaAbs}`);
2604
+ if (Array.isArray(enrichmentPlan.unapplied_settings) && enrichmentPlan.unapplied_settings.length > 0) {
2605
+ console.log(`Warning: unresolved enrichment settings: ${enrichmentPlan.unapplied_settings.length}`);
2606
+ }
2607
+ return;
2608
+ }
2609
+ if (subcommand === 'validate') {
2610
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2611
+ const inputPathOverride = getFlagValue(subArgs, '--input');
2612
+ const outputPath = getFlagValue(subArgs, '--output');
2613
+ const pretty = hasFlag(subArgs, '--pretty');
2614
+ const result = (0, onboarding_1.validateOnboarding)({
2615
+ configPath,
2616
+ inputPathOverride: inputPathOverride || undefined,
2617
+ persist: true,
2618
+ });
2619
+ const output = JSON.stringify(result, null, pretty ? 2 : undefined);
2620
+ if (outputPath) {
2621
+ fs.writeFileSync(outputPath, output, 'utf-8');
2622
+ }
2623
+ else {
2624
+ console.log(output);
2625
+ }
2626
+ if (result.status !== 'validated') {
2627
+ process.exit(1);
2628
+ }
2629
+ return;
2630
+ }
2631
+ if (subcommand === 'complete') {
2632
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2633
+ const completedBy = getFlagValue(subArgs, '--completed-by');
2634
+ const outputPath = getFlagValue(subArgs, '--output');
2635
+ const pretty = hasFlag(subArgs, '--pretty');
2636
+ const result = (0, onboarding_1.completeOnboarding)({
2637
+ configPath,
2638
+ completedBy: completedBy || undefined,
2639
+ });
2640
+ const output = JSON.stringify(result, null, pretty ? 2 : undefined);
2641
+ if (outputPath) {
2642
+ fs.writeFileSync(outputPath, output, 'utf-8');
2643
+ }
2644
+ else {
2645
+ console.log(output);
2646
+ }
2647
+ if (result.status !== 'completed') {
2648
+ process.exit(1);
2649
+ }
2650
+ return;
2651
+ }
2652
+ if (subcommand === 'status') {
2653
+ const configPath = getFlagValue(subArgs, '--config') || 'monora.yml';
2654
+ const pretty = hasFlag(subArgs, '--pretty');
2655
+ const result = (0, onboarding_1.getOnboardingStatus)({ configPath });
2656
+ console.log(JSON.stringify(result, null, pretty ? 2 : undefined));
2657
+ return;
2658
+ }
2659
+ console.error(`Unknown onboard subcommand: ${subcommand}`);
2660
+ process.exit(1);
2661
+ }
1497
2662
  const RETRY_QUEUE_STATS_FILENAME = '.monora_retry_queue_stats.json';
1498
2663
  function resolveRetryQueuePaths(config, overridePath) {
1499
2664
  const warnings = [];
@@ -1674,6 +2839,284 @@ async function runRetryQueue(args) {
1674
2839
  process.exit(1);
1675
2840
  }
1676
2841
  }
2842
+ async function runProductionCheck(args) {
2843
+ const configPath = getFlagValue(args, '--config') || 'monora.yml';
2844
+ const jsonOutput = hasFlag(args, '--json');
2845
+ const showFix = hasFlag(args, '--fix');
2846
+ // Detect environment
2847
+ const envDetection = (0, config_1.detectEnvironment)();
2848
+ const suggestedPreset = (0, config_1.suggestPreset)();
2849
+ // Load config
2850
+ let config;
2851
+ try {
2852
+ config = (0, config_1.loadConfig)({ configPath });
2853
+ }
2854
+ catch {
2855
+ config = (0, config_1.loadConfig)({});
2856
+ }
2857
+ const checks = [];
2858
+ // Check 1: Signing enabled
2859
+ const signingEnabled = config.signing?.enabled === true;
2860
+ checks.push({
2861
+ name: 'signing_enabled',
2862
+ passed: signingEnabled,
2863
+ message: signingEnabled
2864
+ ? 'Event signing is enabled'
2865
+ : 'Event signing is disabled - events cannot be verified for authenticity',
2866
+ fix: signingEnabled ? undefined : 'Set signing.enabled: true and configure signing.key_env or signing.key_file',
2867
+ });
2868
+ // Check 2: WAL enabled
2869
+ const walEnabled = config.wal?.enabled === true;
2870
+ checks.push({
2871
+ name: 'wal_enabled',
2872
+ passed: walEnabled,
2873
+ message: walEnabled
2874
+ ? 'Write-ahead log is enabled for crash resilience'
2875
+ : 'Write-ahead log is disabled - events may be lost on crash',
2876
+ fix: walEnabled ? undefined : 'Set wal.enabled: true',
2877
+ });
2878
+ // Check 3: Hash chain verification
2879
+ const verifyOnShutdown = config.immutability?.verify_on_shutdown === true;
2880
+ const verifyOnEmit = config.immutability?.verify_on_emit === true;
2881
+ const hasVerification = verifyOnShutdown || verifyOnEmit;
2882
+ checks.push({
2883
+ name: 'hash_verification',
2884
+ passed: hasVerification,
2885
+ message: hasVerification
2886
+ ? `Hash chain verification enabled (on_emit: ${verifyOnEmit}, on_shutdown: ${verifyOnShutdown})`
2887
+ : 'Hash chain verification is disabled - tampering may go undetected',
2888
+ fix: hasVerification ? undefined : 'Set immutability.verify_on_shutdown: true',
2889
+ });
2890
+ // Check 4: No stdout sink in production
2891
+ const sinks = config.sinks || [];
2892
+ const hasStdoutSink = sinks.some((s) => s.type === 'stdout');
2893
+ const stdoutOk = envDetection.environment !== 'production' || !hasStdoutSink;
2894
+ checks.push({
2895
+ name: 'no_stdout_in_production',
2896
+ passed: stdoutOk,
2897
+ message: stdoutOk
2898
+ ? hasStdoutSink
2899
+ ? 'Stdout sink is acceptable in non-production environment'
2900
+ : 'No stdout sink configured'
2901
+ : 'Stdout sink detected in production - events may be lost',
2902
+ fix: stdoutOk ? undefined : 'Replace stdout sink with file or https sink for production',
2903
+ });
2904
+ // Check 5: Has persistent sink
2905
+ const hasPersistentSink = sinks.some((s) => s.type === 'file' || s.type === 'https');
2906
+ checks.push({
2907
+ name: 'persistent_sink',
2908
+ passed: hasPersistentSink,
2909
+ message: hasPersistentSink
2910
+ ? 'Persistent sink (file or https) is configured'
2911
+ : 'No persistent sink configured - events will not be stored',
2912
+ fix: hasPersistentSink ? undefined : 'Add a file or https sink to persist events',
2913
+ });
2914
+ // Check 6: Environment explicitly set
2915
+ const envExplicit = config.defaults?.environment && config.defaults.environment !== 'dev';
2916
+ checks.push({
2917
+ name: 'environment_set',
2918
+ passed: !!envExplicit,
2919
+ message: envExplicit
2920
+ ? `Environment explicitly set to: ${config.defaults?.environment}`
2921
+ : 'Environment defaults to "dev" - consider setting explicitly',
2922
+ fix: envExplicit ? undefined : 'Set defaults.environment to your target environment',
2923
+ });
2924
+ // Check 7: Service name set
2925
+ const hasServiceName = !!config.defaults?.service_name;
2926
+ checks.push({
2927
+ name: 'service_name_set',
2928
+ passed: hasServiceName,
2929
+ message: hasServiceName
2930
+ ? `Service name set: ${config.defaults?.service_name}`
2931
+ : 'Service name not set - events will be harder to identify',
2932
+ fix: hasServiceName ? undefined : 'Set defaults.service_name to identify your service',
2933
+ });
2934
+ // Build result
2935
+ const passedCount = checks.filter((c) => c.passed).length;
2936
+ const result = {
2937
+ passed: passedCount === checks.length,
2938
+ environment: {
2939
+ detected: envDetection.environment,
2940
+ source: envDetection.source,
2941
+ confidence: envDetection.confidence,
2942
+ suggested_preset: suggestedPreset,
2943
+ },
2944
+ checks,
2945
+ summary: {
2946
+ total: checks.length,
2947
+ passed: passedCount,
2948
+ failed: checks.length - passedCount,
2949
+ },
2950
+ };
2951
+ if (jsonOutput) {
2952
+ console.log(JSON.stringify(result, null, 2));
2953
+ }
2954
+ else {
2955
+ console.log('\n=== Monora Production Readiness Check ===\n');
2956
+ console.log('Environment Detection:');
2957
+ console.log(` Detected: ${result.environment.detected}`);
2958
+ console.log(` Source: ${result.environment.source}`);
2959
+ console.log(` Confidence: ${result.environment.confidence}`);
2960
+ console.log(` Suggested preset: ${result.environment.suggested_preset}`);
2961
+ console.log('');
2962
+ console.log('Checks:');
2963
+ for (const check of checks) {
2964
+ const status = check.passed ? '✓' : '✗';
2965
+ const color = check.passed ? '\x1b[32m' : '\x1b[31m';
2966
+ const reset = '\x1b[0m';
2967
+ console.log(` ${color}${status}${reset} ${check.name}: ${check.message}`);
2968
+ if (!check.passed && showFix && check.fix) {
2969
+ console.log(` → Fix: ${check.fix}`);
2970
+ }
2971
+ }
2972
+ console.log('');
2973
+ console.log('Summary:');
2974
+ console.log(` Total: ${result.summary.total}`);
2975
+ console.log(` Passed: ${result.summary.passed}`);
2976
+ console.log(` Failed: ${result.summary.failed}`);
2977
+ console.log('');
2978
+ if (result.passed) {
2979
+ console.log('\x1b[32m✓ All production readiness checks passed!\x1b[0m');
2980
+ }
2981
+ else {
2982
+ console.log('\x1b[33m⚠ Some checks failed. Run with --fix to see remediation steps.\x1b[0m');
2983
+ }
2984
+ }
2985
+ if (!result.passed) {
2986
+ process.exit(1);
2987
+ }
2988
+ }
2989
+ async function runDetectEnv(args) {
2990
+ const jsonOutput = hasFlag(args, '--json');
2991
+ const detection = (0, config_1.detectEnvironment)();
2992
+ const suggested = (0, config_1.suggestPreset)();
2993
+ if (jsonOutput) {
2994
+ console.log(JSON.stringify({
2995
+ ...detection,
2996
+ suggested_preset: suggested,
2997
+ }, null, 2));
2998
+ }
2999
+ else {
3000
+ console.log(`Environment: ${detection.environment}`);
3001
+ console.log(`Source: ${detection.source}`);
3002
+ console.log(`Confidence: ${detection.confidence}`);
3003
+ console.log(`Suggested preset: ${suggested}`);
3004
+ if (Object.keys(detection.context || {}).length > 0) {
3005
+ console.log('Context:');
3006
+ for (const [key, value] of Object.entries(detection.context || {})) {
3007
+ console.log(` ${key}: ${value}`);
3008
+ }
3009
+ }
3010
+ }
3011
+ }
3012
+ function diffConfigs(from, to, prefix = '') {
3013
+ const diffs = [];
3014
+ const allKeys = new Set([...Object.keys(from), ...Object.keys(to)]);
3015
+ for (const key of allKeys) {
3016
+ const path = prefix ? `${prefix}.${key}` : key;
3017
+ const fromVal = from[key];
3018
+ const toVal = to[key];
3019
+ if (fromVal === undefined && toVal !== undefined) {
3020
+ diffs.push({ path, from: undefined, to: toVal, action: 'add' });
3021
+ }
3022
+ else if (fromVal !== undefined && toVal === undefined) {
3023
+ diffs.push({ path, from: fromVal, to: undefined, action: 'remove' });
3024
+ }
3025
+ else if (typeof fromVal === 'object' && typeof toVal === 'object' && fromVal !== null && toVal !== null && !Array.isArray(fromVal) && !Array.isArray(toVal)) {
3026
+ diffs.push(...diffConfigs(fromVal, toVal, path));
3027
+ }
3028
+ else if (JSON.stringify(fromVal) !== JSON.stringify(toVal)) {
3029
+ diffs.push({ path, from: fromVal, to: toVal, action: 'change' });
3030
+ }
3031
+ }
3032
+ return diffs;
3033
+ }
3034
+ const VALID_PRESETS = [
3035
+ 'minimal', 'dev', 'development', 'production', 'compliance', 'poc',
3036
+ 'strict_enterprise', 'default_secure', 'experimental', 'audit_first', 'low_latency'
3037
+ ];
3038
+ async function runUpgradePreset(args) {
3039
+ const fromPreset = getFlagValue(args, '--from');
3040
+ const toPreset = getFlagValue(args, '--to');
3041
+ const outputPath = getFlagValue(args, '--output');
3042
+ const jsonOutput = hasFlag(args, '--json');
3043
+ if (!fromPreset || !toPreset) {
3044
+ console.error('Error: --from and --to presets are required');
3045
+ console.error('Usage: monora upgrade-preset --from <preset> --to <preset>');
3046
+ console.error(`Valid presets: ${VALID_PRESETS.join(', ')}`);
3047
+ process.exit(1);
3048
+ }
3049
+ if (!VALID_PRESETS.includes(fromPreset)) {
3050
+ console.error(`Error: Invalid --from preset '${fromPreset}'`);
3051
+ console.error(`Valid presets: ${VALID_PRESETS.join(', ')}`);
3052
+ process.exit(1);
3053
+ }
3054
+ if (!VALID_PRESETS.includes(toPreset)) {
3055
+ console.error(`Error: Invalid --to preset '${toPreset}'`);
3056
+ console.error(`Valid presets: ${VALID_PRESETS.join(', ')}`);
3057
+ process.exit(1);
3058
+ }
3059
+ const fromConfig = (0, config_1.getPresetConfig)(fromPreset);
3060
+ const toConfig = (0, config_1.getPresetConfig)(toPreset);
3061
+ const diffs = diffConfigs(fromConfig, toConfig);
3062
+ const result = {
3063
+ from_preset: fromPreset,
3064
+ to_preset: toPreset,
3065
+ changes: diffs.map(d => ({
3066
+ path: d.path,
3067
+ action: d.action,
3068
+ from: d.from,
3069
+ to: d.to,
3070
+ })),
3071
+ summary: {
3072
+ total: diffs.length,
3073
+ added: diffs.filter(d => d.action === 'add').length,
3074
+ removed: diffs.filter(d => d.action === 'remove').length,
3075
+ changed: diffs.filter(d => d.action === 'change').length,
3076
+ },
3077
+ };
3078
+ if (jsonOutput) {
3079
+ console.log(JSON.stringify(result, null, 2));
3080
+ }
3081
+ else {
3082
+ console.log(`\n=== Upgrade from '${fromPreset}' to '${toPreset}' ===\n`);
3083
+ if (diffs.length === 0) {
3084
+ console.log('No configuration changes required.');
3085
+ }
3086
+ else {
3087
+ console.log('Configuration changes:\n');
3088
+ for (const diff of diffs) {
3089
+ const actionColor = diff.action === 'add' ? '\x1b[32m+' : diff.action === 'remove' ? '\x1b[31m-' : '\x1b[33m~';
3090
+ const reset = '\x1b[0m';
3091
+ console.log(`${actionColor} ${diff.path}${reset}`);
3092
+ if (diff.action === 'change') {
3093
+ console.log(` from: ${JSON.stringify(diff.from)}`);
3094
+ console.log(` to: ${JSON.stringify(diff.to)}`);
3095
+ }
3096
+ else if (diff.action === 'add') {
3097
+ console.log(` value: ${JSON.stringify(diff.to)}`);
3098
+ }
3099
+ else if (diff.action === 'remove') {
3100
+ console.log(` was: ${JSON.stringify(diff.from)}`);
3101
+ }
3102
+ }
3103
+ console.log(`\nSummary: ${result.summary.total} changes`);
3104
+ console.log(` Added: ${result.summary.added}`);
3105
+ console.log(` Removed: ${result.summary.removed}`);
3106
+ console.log(` Changed: ${result.summary.changed}`);
3107
+ }
3108
+ if (outputPath) {
3109
+ const ext = path.extname(outputPath).toLowerCase();
3110
+ const content = ext === '.json' ? JSON.stringify(toConfig, null, 2) : yaml.dump(toConfig);
3111
+ fs.writeFileSync(outputPath, content, 'utf-8');
3112
+ console.log(`\nWrote '${toPreset}' preset configuration to: ${outputPath}`);
3113
+ }
3114
+ else {
3115
+ console.log('\nTo apply this preset, run:');
3116
+ console.log(` monora upgrade-preset --from ${fromPreset} --to ${toPreset} --output monora.yml`);
3117
+ }
3118
+ }
3119
+ }
1677
3120
  async function main() {
1678
3121
  const parsed = parseArgs(process.argv);
1679
3122
  if (!parsed.command || parsed.command === '--help' || parsed.command === '-h') {
@@ -1688,6 +3131,15 @@ async function main() {
1688
3131
  await runDoctor(parsed.args);
1689
3132
  return;
1690
3133
  }
3134
+ if (parsed.command === 'config') {
3135
+ const subcommand = parsed.args[0];
3136
+ if (subcommand === 'fix') {
3137
+ await runConfigFix(parsed.args.slice(1));
3138
+ return;
3139
+ }
3140
+ usage();
3141
+ process.exit(1);
3142
+ }
1691
3143
  if (parsed.command === 'init') {
1692
3144
  const options = parseInitOptions(parsed.args);
1693
3145
  if (fs.existsSync(options.path) && !options.force && !options.yes) {
@@ -1699,7 +3151,12 @@ async function main() {
1699
3151
  process.exit(1);
1700
3152
  }
1701
3153
  }
1702
- await runInitWizard(options.path, options.format, options.yes, options.force);
3154
+ await runInitWizard(options.path, options.format, options.yes, options.force, options.advanced, options.preset);
3155
+ return;
3156
+ }
3157
+ // New 'start' command for zero-code instrumentation
3158
+ if (parsed.command === 'start') {
3159
+ await runStart(parsed.args);
1703
3160
  return;
1704
3161
  }
1705
3162
  if (parsed.command === 'report') {
@@ -1718,6 +3175,10 @@ async function main() {
1718
3175
  await runTrustPackage(parseTrustPackageOptions(parsed.args));
1719
3176
  return;
1720
3177
  }
3178
+ if (parsed.command === 'aims') {
3179
+ await runAims(parsed.args);
3180
+ return;
3181
+ }
1721
3182
  if (parsed.command === 'ai-act-report') {
1722
3183
  await runAIActReport(parseAIActReportOptions(parsed.args));
1723
3184
  return;
@@ -1758,6 +3219,30 @@ async function main() {
1758
3219
  await runStandardsCheck(parsed.args);
1759
3220
  return;
1760
3221
  }
3222
+ if (parsed.command === 'onboard') {
3223
+ await runOnboard(parsed.args);
3224
+ return;
3225
+ }
3226
+ if (parsed.command === 'schema') {
3227
+ await runSchema(parsed.args);
3228
+ return;
3229
+ }
3230
+ if (parsed.command === 'model') {
3231
+ await runModel(parsed.args);
3232
+ return;
3233
+ }
3234
+ if (parsed.command === 'production-check') {
3235
+ await runProductionCheck(parsed.args);
3236
+ return;
3237
+ }
3238
+ if (parsed.command === 'detect-env') {
3239
+ await runDetectEnv(parsed.args);
3240
+ return;
3241
+ }
3242
+ if (parsed.command === 'upgrade-preset') {
3243
+ await runUpgradePreset(parsed.args);
3244
+ return;
3245
+ }
1761
3246
  usage();
1762
3247
  }
1763
3248
  main().catch((err) => {