monora-ai 1.6.0 ā 1.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/report.d.ts.map +1 -1
- package/dist/report.js +143 -46
- package/dist/reporting.js +54 -8
- package/package.json +3 -1
- package/scripts/copy-files.js +10 -0
- package/scripts/postinstall.js +146 -0
package/dist/report.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAIxC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAelE;
|
|
1
|
+
{"version":3,"file":"report.d.ts","sourceRoot":"","sources":["../src/report.ts"],"names":[],"mappings":"AAAA;;GAEG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAIxC,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,CAelE;AAqJD,wBAAgB,WAAW,CACzB,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,EAClC,QAAQ,CAAC,EAAE,YAAY,CAAC,UAAU,CAAC,GAClC,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAkMrB;AAED,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAEzE;AAED,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,IAAI,CAsD7E"}
|
package/dist/report.js
CHANGED
|
@@ -78,6 +78,99 @@ function coerceTokenCount(value) {
|
|
|
78
78
|
const numberValue = Number(value);
|
|
79
79
|
return Number.isFinite(numberValue) ? numberValue : null;
|
|
80
80
|
}
|
|
81
|
+
function resolvePolicyName(body) {
|
|
82
|
+
for (const key of ['policy_name', 'policy', 'policy_id', 'policyId']) {
|
|
83
|
+
const value = body[key];
|
|
84
|
+
if (value) {
|
|
85
|
+
const candidate = String(value).trim();
|
|
86
|
+
if (candidate) {
|
|
87
|
+
return candidate;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
if (body.policy && typeof body.policy === 'object') {
|
|
92
|
+
for (const key of ['name', 'id', 'policy_name']) {
|
|
93
|
+
const value = body.policy[key];
|
|
94
|
+
if (value) {
|
|
95
|
+
const candidate = String(value).trim();
|
|
96
|
+
if (candidate) {
|
|
97
|
+
return candidate;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
if (body.data_handling && typeof body.data_handling === 'object' && body.data_handling.action) {
|
|
103
|
+
return 'data_handling.block';
|
|
104
|
+
}
|
|
105
|
+
return 'UNKNOWN_POLICY';
|
|
106
|
+
}
|
|
107
|
+
function resolvePolicyMessage(body) {
|
|
108
|
+
if (body.message) {
|
|
109
|
+
const candidate = String(body.message).trim();
|
|
110
|
+
if (candidate) {
|
|
111
|
+
return candidate;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (body.data_handling && typeof body.data_handling === 'object') {
|
|
115
|
+
const rules = body.data_handling.rules;
|
|
116
|
+
if (Array.isArray(rules) && rules.length > 0) {
|
|
117
|
+
return `Sensitive data matched rules: ${rules.map(String).join(', ')}`;
|
|
118
|
+
}
|
|
119
|
+
if (body.data_handling.action) {
|
|
120
|
+
return `Data handling policy violation (${body.data_handling.action})`;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return 'Policy violation recorded';
|
|
124
|
+
}
|
|
125
|
+
function normalizeUsage(usage) {
|
|
126
|
+
if (!usage || typeof usage !== 'object') {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
let prompt = coerceTokenCount(usage.prompt_tokens);
|
|
130
|
+
let completion = coerceTokenCount(usage.completion_tokens);
|
|
131
|
+
if (prompt === null) {
|
|
132
|
+
prompt = coerceTokenCount(usage.input_tokens);
|
|
133
|
+
}
|
|
134
|
+
if (completion === null) {
|
|
135
|
+
completion = coerceTokenCount(usage.output_tokens);
|
|
136
|
+
}
|
|
137
|
+
const total = coerceTokenCount(usage.total_tokens);
|
|
138
|
+
if (prompt === null && completion === null && total === null) {
|
|
139
|
+
return null;
|
|
140
|
+
}
|
|
141
|
+
const safePrompt = prompt ?? 0;
|
|
142
|
+
const safeCompletion = completion ?? 0;
|
|
143
|
+
const safeTotal = total ?? safePrompt + safeCompletion;
|
|
144
|
+
return { prompt: safePrompt, completion: safeCompletion, total: safeTotal };
|
|
145
|
+
}
|
|
146
|
+
function extractUsage(body) {
|
|
147
|
+
const response = body.response;
|
|
148
|
+
if (response && typeof response === 'object') {
|
|
149
|
+
const normalized = normalizeUsage(response.usage);
|
|
150
|
+
if (normalized) {
|
|
151
|
+
return normalized;
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
const usage = normalizeUsage(body.usage);
|
|
155
|
+
if (usage) {
|
|
156
|
+
return usage;
|
|
157
|
+
}
|
|
158
|
+
const tokenUsage = normalizeUsage(body.token_usage);
|
|
159
|
+
if (tokenUsage) {
|
|
160
|
+
return tokenUsage;
|
|
161
|
+
}
|
|
162
|
+
return null;
|
|
163
|
+
}
|
|
164
|
+
function classifyPolicyViolation(policyName) {
|
|
165
|
+
const lowered = policyName.toLowerCase();
|
|
166
|
+
if (lowered.includes('unknown_model')) {
|
|
167
|
+
return 'unknown';
|
|
168
|
+
}
|
|
169
|
+
if (['denylist', 'blocklist', 'forbidden'].some((token) => lowered.includes(token))) {
|
|
170
|
+
return 'forbidden';
|
|
171
|
+
}
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
81
174
|
function compilePatterns(patterns) {
|
|
82
175
|
return patterns.map((pattern) => {
|
|
83
176
|
const regexPattern = pattern
|
|
@@ -123,6 +216,31 @@ function buildReport(events, policies) {
|
|
|
123
216
|
const usedAllowlistPatterns = new Set();
|
|
124
217
|
const missingUsageModels = new Set();
|
|
125
218
|
let missingUsageEvents = 0;
|
|
219
|
+
for (const event of filteredEvents) {
|
|
220
|
+
const body = event && typeof event.body === 'object' && event.body
|
|
221
|
+
? event.body
|
|
222
|
+
: {};
|
|
223
|
+
if (body.status === 'policy_violation') {
|
|
224
|
+
const policyName = resolvePolicyName(body) || 'UNKNOWN_POLICY';
|
|
225
|
+
const message = resolvePolicyMessage(body) || 'Policy violation recorded';
|
|
226
|
+
violations.push({
|
|
227
|
+
timestamp: event.timestamp,
|
|
228
|
+
model: body.model,
|
|
229
|
+
policy: policyName,
|
|
230
|
+
message,
|
|
231
|
+
});
|
|
232
|
+
const model = normalizeModelName(body.model);
|
|
233
|
+
if (model) {
|
|
234
|
+
const classification = classifyPolicyViolation(policyName);
|
|
235
|
+
if (classification === 'forbidden') {
|
|
236
|
+
forbiddenModelsBlocked.add(model);
|
|
237
|
+
}
|
|
238
|
+
else if (classification === 'unknown') {
|
|
239
|
+
unknownModelsUsed.add(model);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
126
244
|
for (const event of filteredEvents) {
|
|
127
245
|
if (event.trace_id) {
|
|
128
246
|
traceIds.add(event.trace_id);
|
|
@@ -141,64 +259,39 @@ function buildReport(events, policies) {
|
|
|
141
259
|
byClassification[event.data_classification] =
|
|
142
260
|
(byClassification[event.data_classification] || 0) + 1;
|
|
143
261
|
}
|
|
144
|
-
const body = event.body
|
|
262
|
+
const body = event && typeof event.body === 'object' && event.body
|
|
263
|
+
? event.body
|
|
264
|
+
: {};
|
|
145
265
|
if (event.event_type === 'llm_call') {
|
|
146
266
|
const model = normalizeModelName(body.model);
|
|
147
|
-
|
|
267
|
+
const isBlocked = body.status === 'policy_violation';
|
|
268
|
+
if (model && !isBlocked) {
|
|
148
269
|
byModel[model] = (byModel[model] || 0) + 1;
|
|
149
270
|
modelsUsed.add(model);
|
|
150
271
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
const total = coerceTokenCount(usage.total_tokens) ??
|
|
158
|
-
(coerceTokenCount(usage.prompt_tokens) !== null ||
|
|
159
|
-
coerceTokenCount(usage.completion_tokens) !== null
|
|
160
|
-
? prompt + completion
|
|
161
|
-
: null);
|
|
162
|
-
if (total === null && prompt === 0 && completion === 0) {
|
|
163
|
-
missingUsageEvents += 1;
|
|
164
|
-
if (model) {
|
|
165
|
-
missingUsageModels.add(model);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
else {
|
|
169
|
-
tokenUsage.total_prompt_tokens += prompt;
|
|
170
|
-
tokenUsage.total_completion_tokens += completion;
|
|
171
|
-
tokenUsage.total_tokens += total ?? 0;
|
|
172
|
-
if (model) {
|
|
173
|
-
if (!tokenUsage.by_model[model]) {
|
|
174
|
-
tokenUsage.by_model[model] = { prompt: 0, completion: 0, total: 0 };
|
|
175
|
-
}
|
|
176
|
-
tokenUsage.by_model[model].prompt += prompt;
|
|
177
|
-
tokenUsage.by_model[model].completion += completion;
|
|
178
|
-
tokenUsage.by_model[model].total += total ?? 0;
|
|
179
|
-
}
|
|
272
|
+
if (!isBlocked) {
|
|
273
|
+
const usage = extractUsage(body);
|
|
274
|
+
if (!usage) {
|
|
275
|
+
missingUsageEvents += 1;
|
|
276
|
+
if (model) {
|
|
277
|
+
missingUsageModels.add(model);
|
|
180
278
|
}
|
|
181
279
|
}
|
|
182
280
|
else {
|
|
183
|
-
|
|
281
|
+
tokenUsage.total_prompt_tokens += usage.prompt;
|
|
282
|
+
tokenUsage.total_completion_tokens += usage.completion;
|
|
283
|
+
tokenUsage.total_tokens += usage.total;
|
|
184
284
|
if (model) {
|
|
185
|
-
|
|
285
|
+
if (!tokenUsage.by_model[model]) {
|
|
286
|
+
tokenUsage.by_model[model] = { prompt: 0, completion: 0, total: 0 };
|
|
287
|
+
}
|
|
288
|
+
tokenUsage.by_model[model].prompt += usage.prompt;
|
|
289
|
+
tokenUsage.by_model[model].completion += usage.completion;
|
|
290
|
+
tokenUsage.by_model[model].total += usage.total;
|
|
186
291
|
}
|
|
187
292
|
}
|
|
188
293
|
}
|
|
189
294
|
}
|
|
190
|
-
if (body.status === 'policy_violation') {
|
|
191
|
-
violations.push({
|
|
192
|
-
timestamp: event.timestamp,
|
|
193
|
-
model: body.model,
|
|
194
|
-
policy: body.policy_name,
|
|
195
|
-
message: body.message,
|
|
196
|
-
});
|
|
197
|
-
const model = normalizeModelName(body.model);
|
|
198
|
-
if (model) {
|
|
199
|
-
forbiddenModelsBlocked.add(model);
|
|
200
|
-
}
|
|
201
|
-
}
|
|
202
295
|
if (body.error) {
|
|
203
296
|
errors.push({
|
|
204
297
|
timestamp: event.timestamp,
|
|
@@ -238,6 +331,9 @@ function buildReport(events, policies) {
|
|
|
238
331
|
allowedModelsUsed.add(model);
|
|
239
332
|
}
|
|
240
333
|
}
|
|
334
|
+
for (const model of modelsUsed) {
|
|
335
|
+
forbiddenModelsBlocked.delete(model);
|
|
336
|
+
}
|
|
241
337
|
for (const model of allowedModelsUsed) {
|
|
242
338
|
unknownModelsUsed.delete(model);
|
|
243
339
|
}
|
|
@@ -255,6 +351,7 @@ function buildReport(events, policies) {
|
|
|
255
351
|
start: timestamps.length ? new Date(Math.min(...timestamps.map((t) => t.getTime()))).toISOString() : null,
|
|
256
352
|
end: timestamps.length ? new Date(Math.max(...timestamps.map((t) => t.getTime()))).toISOString() : null,
|
|
257
353
|
};
|
|
354
|
+
const unknownModelsPayload = policies || unknownModelsUsed.size > 0 ? Array.from(unknownModelsUsed).sort() : [];
|
|
258
355
|
return {
|
|
259
356
|
total_events: filteredEvents.length,
|
|
260
357
|
traces: traceIds.size,
|
|
@@ -269,7 +366,7 @@ function buildReport(events, policies) {
|
|
|
269
366
|
model_compliance: {
|
|
270
367
|
allowed_models_used: Array.from(allowedModelsUsed).sort(),
|
|
271
368
|
forbidden_models_blocked: Array.from(forbiddenModelsBlocked).sort(),
|
|
272
|
-
unknown_models_used:
|
|
369
|
+
unknown_models_used: unknownModelsPayload,
|
|
273
370
|
unused_allowlist_patterns: unusedAllowlistPatterns.sort(),
|
|
274
371
|
},
|
|
275
372
|
};
|
package/dist/reporting.js
CHANGED
|
@@ -365,24 +365,67 @@ function verifyChainStatusWithProof(events, config) {
|
|
|
365
365
|
return ['failed', exc instanceof Error ? exc.message : String(exc), null];
|
|
366
366
|
}
|
|
367
367
|
}
|
|
368
|
+
const INVALID_IDENTIFIER_VALUES = new Set(['__main__.py', '__main__', 'unknown']);
|
|
369
|
+
function sanitizeIdentifier(value) {
|
|
370
|
+
if (value === null || value === undefined) {
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
const candidate = String(value).trim();
|
|
374
|
+
if (!candidate) {
|
|
375
|
+
return null;
|
|
376
|
+
}
|
|
377
|
+
const base = candidate.split(/[\\/]/).pop() || '';
|
|
378
|
+
if (!base) {
|
|
379
|
+
return null;
|
|
380
|
+
}
|
|
381
|
+
if (INVALID_IDENTIFIER_VALUES.has(base.toLowerCase())) {
|
|
382
|
+
return null;
|
|
383
|
+
}
|
|
384
|
+
return base;
|
|
385
|
+
}
|
|
386
|
+
function normalizeEnvironmentValue(value) {
|
|
387
|
+
if (typeof value !== 'string') {
|
|
388
|
+
return 'dev';
|
|
389
|
+
}
|
|
390
|
+
const normalized = value.trim();
|
|
391
|
+
if (!normalized) {
|
|
392
|
+
return 'dev';
|
|
393
|
+
}
|
|
394
|
+
if (normalized.toLowerCase() === 'development') {
|
|
395
|
+
return 'dev';
|
|
396
|
+
}
|
|
397
|
+
return normalized;
|
|
398
|
+
}
|
|
368
399
|
function resolveProjectName(config) {
|
|
369
|
-
const projectName = process.env.MONORA_PROJECT_NAME ||
|
|
370
|
-
process.env.PROJECT_NAME ||
|
|
371
|
-
config?.defaults?.service_name ||
|
|
400
|
+
const projectName = sanitizeIdentifier(process.env.MONORA_PROJECT_NAME) ||
|
|
401
|
+
sanitizeIdentifier(process.env.PROJECT_NAME) ||
|
|
402
|
+
sanitizeIdentifier(config?.defaults?.service_name) ||
|
|
372
403
|
'monora';
|
|
373
|
-
if (
|
|
404
|
+
if (projectName === 'monora') {
|
|
374
405
|
console.error('Monora: project name missing; defaulting to "monora"');
|
|
375
|
-
return 'monora';
|
|
376
406
|
}
|
|
377
407
|
return projectName;
|
|
378
408
|
}
|
|
379
409
|
function resolveEnvironment(config) {
|
|
380
|
-
|
|
410
|
+
const rawEnv = config?.defaults?.environment || process.env.MONORA_ENV || 'dev';
|
|
411
|
+
return normalizeEnvironmentValue(rawEnv);
|
|
381
412
|
}
|
|
382
413
|
function shouldRedactHost(config) {
|
|
383
414
|
const reporting = config?.reporting || {};
|
|
384
415
|
return reporting.redact_host !== false;
|
|
385
416
|
}
|
|
417
|
+
function applyTrustProofOverrides(events, environment) {
|
|
418
|
+
return events.map((event) => {
|
|
419
|
+
if (!event || typeof event !== 'object') {
|
|
420
|
+
return event;
|
|
421
|
+
}
|
|
422
|
+
const currentEnv = event.environment;
|
|
423
|
+
if (!currentEnv || normalizeEnvironmentValue(currentEnv) !== environment) {
|
|
424
|
+
return { ...event, environment };
|
|
425
|
+
}
|
|
426
|
+
return event;
|
|
427
|
+
});
|
|
428
|
+
}
|
|
386
429
|
function redactEventHosts(events, prefix) {
|
|
387
430
|
const mapping = new Map();
|
|
388
431
|
return events.map((event) => {
|
|
@@ -405,7 +448,11 @@ function redactEventHosts(events, prefix) {
|
|
|
405
448
|
function buildTrustProofBundle(traceId, report, events, chainProof, artifacts, config) {
|
|
406
449
|
const redactHosts = shouldRedactHost(config);
|
|
407
450
|
const redactionPrefix = 'host-sha256:';
|
|
408
|
-
const
|
|
451
|
+
const environment = resolveEnvironment(config);
|
|
452
|
+
const normalizedEvents = applyTrustProofOverrides(events, environment);
|
|
453
|
+
const sanitizedEvents = redactHosts
|
|
454
|
+
? redactEventHosts(normalizedEvents, redactionPrefix)
|
|
455
|
+
: normalizedEvents;
|
|
409
456
|
// Compute events digest
|
|
410
457
|
const eventsDigestHash = (0, verify_1.computeEventsDigest)(sanitizedEvents);
|
|
411
458
|
// Build artifact list for bundle
|
|
@@ -422,7 +469,6 @@ function buildTrustProofBundle(traceId, report, events, chainProof, artifacts, c
|
|
|
422
469
|
}
|
|
423
470
|
// Get project name from config
|
|
424
471
|
const projectName = resolveProjectName(config);
|
|
425
|
-
const environment = resolveEnvironment(config);
|
|
426
472
|
// Build the bundle
|
|
427
473
|
const reportBytes = (0, attestation_1.serializeReport)(report);
|
|
428
474
|
let bundle = (0, attestation_1.buildAttestationBundle)(report, reportBytes, undefined, {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "monora-ai",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.7.0",
|
|
4
4
|
"description": "Lightweight governance and trace SDK for AI systems",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -11,10 +11,12 @@
|
|
|
11
11
|
"build": "tsc && node scripts/copy-files.js",
|
|
12
12
|
"test": "jest",
|
|
13
13
|
"prepublishOnly": "npm run build",
|
|
14
|
+
"postinstall": "node scripts/postinstall.js",
|
|
14
15
|
"clean": "rm -rf dist"
|
|
15
16
|
},
|
|
16
17
|
"files": [
|
|
17
18
|
"dist",
|
|
19
|
+
"scripts",
|
|
18
20
|
"README.md",
|
|
19
21
|
"LICENSE"
|
|
20
22
|
],
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
3
|
+
|
|
4
|
+
const rootDir = path.resolve(__dirname, '..');
|
|
5
|
+
const srcPath = path.join(rootDir, 'src', 'registryData.json');
|
|
6
|
+
const distDir = path.join(rootDir, 'dist');
|
|
7
|
+
const destPath = path.join(distDir, 'registryData.json');
|
|
8
|
+
|
|
9
|
+
fs.mkdirSync(distDir, { recursive: true });
|
|
10
|
+
fs.copyFileSync(srcPath, destPath);
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* Postinstall script for Monora SDK
|
|
4
|
+
* Automatically runs the setup wizard after npm install
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
const { execSync, spawn } = require('child_process');
|
|
8
|
+
const fs = require('fs');
|
|
9
|
+
const path = require('path');
|
|
10
|
+
|
|
11
|
+
// Check if we're in a CI environment or non-interactive terminal
|
|
12
|
+
function isCI() {
|
|
13
|
+
return !!(
|
|
14
|
+
process.env.CI ||
|
|
15
|
+
process.env.CONTINUOUS_INTEGRATION ||
|
|
16
|
+
process.env.BUILD_NUMBER ||
|
|
17
|
+
process.env.GITHUB_ACTIONS ||
|
|
18
|
+
process.env.GITLAB_CI ||
|
|
19
|
+
process.env.CIRCLECI ||
|
|
20
|
+
process.env.TRAVIS ||
|
|
21
|
+
process.env.JENKINS_URL ||
|
|
22
|
+
process.env.MONORA_SKIP_POSTINSTALL
|
|
23
|
+
);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function isTTY() {
|
|
27
|
+
return process.stdout.isTTY && process.stdin.isTTY;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function findProjectRoot() {
|
|
31
|
+
// Walk up from current directory to find package.json (the user's project)
|
|
32
|
+
let dir = process.cwd();
|
|
33
|
+
const maxLevels = 10;
|
|
34
|
+
|
|
35
|
+
for (let i = 0; i < maxLevels; i++) {
|
|
36
|
+
const pkgPath = path.join(dir, 'package.json');
|
|
37
|
+
if (fs.existsSync(pkgPath)) {
|
|
38
|
+
try {
|
|
39
|
+
const pkg = JSON.parse(fs.readFileSync(pkgPath, 'utf8'));
|
|
40
|
+
// Skip if this is the monora-ai package itself
|
|
41
|
+
if (pkg.name !== 'monora-ai') {
|
|
42
|
+
return dir;
|
|
43
|
+
}
|
|
44
|
+
} catch (e) {
|
|
45
|
+
// Continue searching
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
const parent = path.dirname(dir);
|
|
49
|
+
if (parent === dir) break;
|
|
50
|
+
dir = parent;
|
|
51
|
+
}
|
|
52
|
+
return process.cwd();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
function configExists(projectRoot) {
|
|
56
|
+
const configFiles = [
|
|
57
|
+
'monora.yml',
|
|
58
|
+
'monora.yaml',
|
|
59
|
+
'monora.json',
|
|
60
|
+
'.monora.yml',
|
|
61
|
+
'.monora.yaml',
|
|
62
|
+
'.monora.json',
|
|
63
|
+
];
|
|
64
|
+
|
|
65
|
+
return configFiles.some(file =>
|
|
66
|
+
fs.existsSync(path.join(projectRoot, file))
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function main() {
|
|
71
|
+
// Skip in CI environments
|
|
72
|
+
if (isCI()) {
|
|
73
|
+
console.log('\nš¦ Monora SDK installed successfully.');
|
|
74
|
+
console.log(' Run "npx monora init" to configure.\n');
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
const projectRoot = findProjectRoot();
|
|
79
|
+
|
|
80
|
+
// Check if config already exists
|
|
81
|
+
if (configExists(projectRoot)) {
|
|
82
|
+
console.log('\nā
Monora SDK installed. Existing configuration detected.\n');
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// Non-interactive terminal - show quick start
|
|
87
|
+
if (!isTTY()) {
|
|
88
|
+
console.log('\nš¦ Monora SDK installed successfully!');
|
|
89
|
+
console.log('');
|
|
90
|
+
console.log('Quick Start:');
|
|
91
|
+
console.log(' 1. Run: npx monora init');
|
|
92
|
+
console.log(' 2. Or use zero-config:');
|
|
93
|
+
console.log(' import { init } from "monora-ai";');
|
|
94
|
+
console.log(' init();');
|
|
95
|
+
console.log('');
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Interactive terminal - run setup wizard
|
|
100
|
+
console.log('\nš Monora SDK installed! Starting setup wizard...\n');
|
|
101
|
+
|
|
102
|
+
try {
|
|
103
|
+
// Run the wizard with --yes for smart defaults
|
|
104
|
+
// Users can run `npx monora init` later for full interactive mode
|
|
105
|
+
const cliPath = path.join(__dirname, '..', 'dist', 'cli.js');
|
|
106
|
+
|
|
107
|
+
if (fs.existsSync(cliPath)) {
|
|
108
|
+
// Run the CLI init command
|
|
109
|
+
const child = spawn('node', [cliPath, 'init', '--yes'], {
|
|
110
|
+
cwd: projectRoot,
|
|
111
|
+
stdio: 'inherit',
|
|
112
|
+
shell: process.platform === 'win32',
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
child.on('error', (err) => {
|
|
116
|
+
console.log('\nš¦ Monora SDK installed.');
|
|
117
|
+
console.log(' Run "npx monora init" to configure manually.\n');
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
child.on('close', (code) => {
|
|
121
|
+
if (code !== 0) {
|
|
122
|
+
console.log('\n Run "npx monora init" to configure manually.\n');
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
} else {
|
|
126
|
+
// CLI not built yet (fresh install), show manual instructions
|
|
127
|
+
console.log('š¦ Monora SDK installed successfully!');
|
|
128
|
+
console.log('');
|
|
129
|
+
console.log('Quick Start:');
|
|
130
|
+
console.log(' Option 1: Run "npx monora init" to configure');
|
|
131
|
+
console.log(' Option 2: Use zero-config in your code:');
|
|
132
|
+
console.log(' import { init } from "monora-ai";');
|
|
133
|
+
console.log(' init();');
|
|
134
|
+
console.log('');
|
|
135
|
+
}
|
|
136
|
+
} catch (err) {
|
|
137
|
+
// Silent fail - don't break npm install
|
|
138
|
+
console.log('\nš¦ Monora SDK installed.');
|
|
139
|
+
console.log(' Run "npx monora init" to configure.\n');
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
main().catch(() => {
|
|
144
|
+
// Never fail the install
|
|
145
|
+
console.log('\nš¦ Monora SDK installed.\n');
|
|
146
|
+
});
|