@memberjunction/codegen-lib 5.29.0 → 5.30.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/Database/codeGenDatabaseProvider.d.ts +5 -1
- package/dist/Database/codeGenDatabaseProvider.d.ts.map +1 -1
- package/dist/Database/codeGenDatabaseProvider.js.map +1 -1
- package/dist/Database/manage-metadata.d.ts +30 -8
- package/dist/Database/manage-metadata.d.ts.map +1 -1
- package/dist/Database/manage-metadata.js +115 -25
- package/dist/Database/manage-metadata.js.map +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js +9 -3
- package/dist/Database/providers/postgresql/PostgreSQLCodeGenProvider.js.map +1 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts +1 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.d.ts.map +1 -1
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js +10 -3
- package/dist/Database/providers/sqlserver/SQLServerCodeGenProvider.js.map +1 -1
- package/dist/Database/sql_codegen.d.ts +10 -0
- package/dist/Database/sql_codegen.d.ts.map +1 -1
- package/dist/Database/sql_codegen.js +30 -7
- package/dist/Database/sql_codegen.js.map +1 -1
- package/dist/Misc/advanced_generation.d.ts.map +1 -1
- package/dist/Misc/advanced_generation.js +16 -0
- package/dist/Misc/advanced_generation.js.map +1 -1
- package/dist/Misc/codegen-reporter.d.ts +231 -0
- package/dist/Misc/codegen-reporter.d.ts.map +1 -0
- package/dist/Misc/codegen-reporter.js +492 -0
- package/dist/Misc/codegen-reporter.js.map +1 -0
- package/dist/Misc/createNewUser.d.ts.map +1 -1
- package/dist/Misc/createNewUser.js +42 -41
- package/dist/Misc/createNewUser.js.map +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/index.js.map +1 -1
- package/dist/runCodeGen.d.ts.map +1 -1
- package/dist/runCodeGen.js +153 -107
- package/dist/runCodeGen.js.map +1 -1
- package/package.json +18 -18
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
import { BaseSingleton } from '@memberjunction/global';
|
|
2
|
+
import * as fs from 'fs/promises';
|
|
3
|
+
import * as path from 'path';
|
|
4
|
+
import * as os from 'os';
|
|
5
|
+
/**
|
|
6
|
+
* Maximum number of run files to keep in `~/.mj/codegen-state/`. Older files are
|
|
7
|
+
* pruned on each `endRun()`. Plain constant — not externally configurable yet.
|
|
8
|
+
*/
|
|
9
|
+
const MAX_RETAINED_RUNS = 50;
|
|
10
|
+
// ----------------------------------------------------------------------------
|
|
11
|
+
// Reporter
|
|
12
|
+
// ----------------------------------------------------------------------------
|
|
13
|
+
/**
|
|
14
|
+
* Singleton reporter for CodeGen runs. Holds state for a single run at a time;
|
|
15
|
+
* call `startRun()` to begin, `endRun()` to emit and reset.
|
|
16
|
+
*/
|
|
17
|
+
export class CodeGenReporter extends BaseSingleton {
|
|
18
|
+
constructor() {
|
|
19
|
+
super();
|
|
20
|
+
// ------------------------------------------------------------------------
|
|
21
|
+
// Run state (reset per run)
|
|
22
|
+
// ------------------------------------------------------------------------
|
|
23
|
+
this._active = false;
|
|
24
|
+
this._runStartMs = 0;
|
|
25
|
+
this._runStartIso = '';
|
|
26
|
+
this._phases = [];
|
|
27
|
+
this._phaseStack = [];
|
|
28
|
+
this._entities = new Map();
|
|
29
|
+
this._llmCalls = [];
|
|
30
|
+
this._counters = this.emptyCounters();
|
|
31
|
+
this._context = {};
|
|
32
|
+
this._notes = [];
|
|
33
|
+
this._currentEntity = null;
|
|
34
|
+
}
|
|
35
|
+
static get Instance() {
|
|
36
|
+
return super.getInstance();
|
|
37
|
+
}
|
|
38
|
+
/** True if a run is currently in progress. */
|
|
39
|
+
get IsActive() {
|
|
40
|
+
return this._active;
|
|
41
|
+
}
|
|
42
|
+
/** Begin capturing a new run. Resets all state from any prior run. */
|
|
43
|
+
startRun() {
|
|
44
|
+
this._active = true;
|
|
45
|
+
this._runStartMs = Date.now();
|
|
46
|
+
this._runStartIso = new Date(this._runStartMs).toISOString();
|
|
47
|
+
this._phases = [];
|
|
48
|
+
this._phaseStack = [];
|
|
49
|
+
this._entities = new Map();
|
|
50
|
+
this._llmCalls = [];
|
|
51
|
+
this._counters = this.emptyCounters();
|
|
52
|
+
this._context = {};
|
|
53
|
+
this._notes = [];
|
|
54
|
+
this._currentEntity = null;
|
|
55
|
+
}
|
|
56
|
+
// ------------------------------------------------------------------------
|
|
57
|
+
// Instrumentation API
|
|
58
|
+
// ------------------------------------------------------------------------
|
|
59
|
+
/**
|
|
60
|
+
* Wrap an async block as a named phase. Phases nest automatically: any
|
|
61
|
+
* phases started while another is open are recorded as its children.
|
|
62
|
+
*
|
|
63
|
+
* If no run is active this becomes a pass-through — safe to call
|
|
64
|
+
* unconditionally.
|
|
65
|
+
*/
|
|
66
|
+
async phase(name, fn) {
|
|
67
|
+
if (!this._active)
|
|
68
|
+
return fn();
|
|
69
|
+
const parent = this._phaseStack[this._phaseStack.length - 1];
|
|
70
|
+
const parentStart = parent ? this.phaseStartAbs(parent) : this._runStartMs;
|
|
71
|
+
const span = {
|
|
72
|
+
name,
|
|
73
|
+
startMs: Date.now() - parentStart,
|
|
74
|
+
durationMs: 0,
|
|
75
|
+
children: [],
|
|
76
|
+
};
|
|
77
|
+
if (parent) {
|
|
78
|
+
parent.children.push(span);
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
this._phases.push(span);
|
|
82
|
+
}
|
|
83
|
+
this._phaseStack.push(span);
|
|
84
|
+
const startedAt = Date.now();
|
|
85
|
+
try {
|
|
86
|
+
return await fn();
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
span.durationMs = Date.now() - startedAt;
|
|
90
|
+
this._phaseStack.pop();
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Wrap per-entity work. Accumulates total time and sub-phase time on the
|
|
95
|
+
* entity record. Also sets the "current entity" so LLM calls recorded
|
|
96
|
+
* inside this block get attributed correctly.
|
|
97
|
+
*/
|
|
98
|
+
async entityPhase(entityName, phaseName, fn) {
|
|
99
|
+
if (!this._active)
|
|
100
|
+
return fn();
|
|
101
|
+
const entry = this.getOrCreateEntity(entityName);
|
|
102
|
+
const prevEntity = this._currentEntity;
|
|
103
|
+
this._currentEntity = entityName;
|
|
104
|
+
const startedAt = Date.now();
|
|
105
|
+
try {
|
|
106
|
+
return await this.phase(`entity:${entityName}:${phaseName}`, fn);
|
|
107
|
+
}
|
|
108
|
+
finally {
|
|
109
|
+
const elapsed = Date.now() - startedAt;
|
|
110
|
+
entry.totalMs += elapsed;
|
|
111
|
+
if (phaseName === 'advancedGeneration') {
|
|
112
|
+
entry.advancedGenerationMs += elapsed;
|
|
113
|
+
}
|
|
114
|
+
this._currentEntity = prevEntity;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Record a single LLM call. Attribution falls back to the entity set by
|
|
119
|
+
* the most recent `entityPhase()` if the caller doesn't supply one.
|
|
120
|
+
*/
|
|
121
|
+
recordLLMCall(call) {
|
|
122
|
+
if (!this._active)
|
|
123
|
+
return;
|
|
124
|
+
const entityName = call.entityName ?? this._currentEntity;
|
|
125
|
+
const entry = {
|
|
126
|
+
entityName,
|
|
127
|
+
promptName: call.promptName,
|
|
128
|
+
model: call.model ?? null,
|
|
129
|
+
tokensIn: call.tokensIn ?? 0,
|
|
130
|
+
tokensOut: call.tokensOut ?? 0,
|
|
131
|
+
costUSD: call.costUSD ?? 0,
|
|
132
|
+
latencyMs: call.latencyMs,
|
|
133
|
+
tsMs: Date.now() - this._runStartMs,
|
|
134
|
+
};
|
|
135
|
+
this._llmCalls.push(entry);
|
|
136
|
+
if (entityName) {
|
|
137
|
+
const ent = this.getOrCreateEntity(entityName);
|
|
138
|
+
ent.llmCalls += 1;
|
|
139
|
+
ent.tokensIn += entry.tokensIn;
|
|
140
|
+
ent.tokensOut += entry.tokensOut;
|
|
141
|
+
ent.costUSD += entry.costUSD;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/** Increment a named counter (default 1). Unknown counter names are allowed. */
|
|
145
|
+
counter(name, delta = 1) {
|
|
146
|
+
if (!this._active)
|
|
147
|
+
return;
|
|
148
|
+
const current = this._counters[name];
|
|
149
|
+
if (typeof current === 'number') {
|
|
150
|
+
this._counters[name] = current + delta;
|
|
151
|
+
}
|
|
152
|
+
else if (current === undefined) {
|
|
153
|
+
this._counters[name] = delta;
|
|
154
|
+
}
|
|
155
|
+
// If it's a Record (e.g., spCalls), callers should use spCallCounter instead.
|
|
156
|
+
}
|
|
157
|
+
/** Increment a specific stored-procedure call count. */
|
|
158
|
+
spCallCounter(spName, delta = 1) {
|
|
159
|
+
if (!this._active)
|
|
160
|
+
return;
|
|
161
|
+
const current = this._counters.spCalls[spName] ?? 0;
|
|
162
|
+
this._counters.spCalls[spName] = current + delta;
|
|
163
|
+
}
|
|
164
|
+
/** Set a one-time context value (platform, mjVersion, etc.). */
|
|
165
|
+
mark(key, value) {
|
|
166
|
+
if (!this._active)
|
|
167
|
+
return;
|
|
168
|
+
this._context[key] = value;
|
|
169
|
+
}
|
|
170
|
+
/** Flag an entity's change status. Used for attribution in the report. */
|
|
171
|
+
flagEntity(entityName, flag, value = true) {
|
|
172
|
+
if (!this._active)
|
|
173
|
+
return;
|
|
174
|
+
const ent = this.getOrCreateEntity(entityName);
|
|
175
|
+
ent.flags[flag] = value;
|
|
176
|
+
}
|
|
177
|
+
/** Append a free-form note (warnings, unexpected conditions, etc.). */
|
|
178
|
+
note(message) {
|
|
179
|
+
if (!this._active)
|
|
180
|
+
return;
|
|
181
|
+
this._notes.push(message);
|
|
182
|
+
}
|
|
183
|
+
// ------------------------------------------------------------------------
|
|
184
|
+
// Emission
|
|
185
|
+
// ------------------------------------------------------------------------
|
|
186
|
+
/**
|
|
187
|
+
* Finalize the run, write the JSON report to disk, and reset state.
|
|
188
|
+
* Returns the written file path (or null) and the report object.
|
|
189
|
+
*
|
|
190
|
+
* Safe to call even if `startRun()` wasn't called (becomes a no-op).
|
|
191
|
+
*/
|
|
192
|
+
async endRun(success) {
|
|
193
|
+
if (!this._active)
|
|
194
|
+
return { filePath: null, report: null };
|
|
195
|
+
const finishedAtMs = Date.now();
|
|
196
|
+
const report = {
|
|
197
|
+
runId: this.makeRunId(),
|
|
198
|
+
startedAt: this._runStartIso,
|
|
199
|
+
finishedAt: new Date(finishedAtMs).toISOString(),
|
|
200
|
+
totalMs: finishedAtMs - this._runStartMs,
|
|
201
|
+
success,
|
|
202
|
+
context: { ...this._context },
|
|
203
|
+
phases: this._phases,
|
|
204
|
+
entities: Array.from(this._entities.values()),
|
|
205
|
+
llmCalls: this._llmCalls,
|
|
206
|
+
counters: this._counters,
|
|
207
|
+
totalCostUSD: this._llmCalls.reduce((sum, c) => sum + c.costUSD, 0),
|
|
208
|
+
totalTokensIn: this._llmCalls.reduce((sum, c) => sum + c.tokensIn, 0),
|
|
209
|
+
totalTokensOut: this._llmCalls.reduce((sum, c) => sum + c.tokensOut, 0),
|
|
210
|
+
notes: this._notes,
|
|
211
|
+
};
|
|
212
|
+
let writtenPath = null;
|
|
213
|
+
try {
|
|
214
|
+
const dir = CodeGenReporter.stateDir();
|
|
215
|
+
await fs.mkdir(dir, { recursive: true });
|
|
216
|
+
writtenPath = path.join(dir, `run-${report.runId}.json`);
|
|
217
|
+
await fs.writeFile(writtenPath, JSON.stringify(report, null, 2), 'utf8');
|
|
218
|
+
await CodeGenReporter.pruneOldRuns();
|
|
219
|
+
}
|
|
220
|
+
catch (err) {
|
|
221
|
+
// Don't fail the CodeGen run because we couldn't write telemetry.
|
|
222
|
+
// eslint-disable-next-line no-console
|
|
223
|
+
console.warn(`[codegen-reporter] Failed to write report: ${err.message}`);
|
|
224
|
+
writtenPath = null;
|
|
225
|
+
}
|
|
226
|
+
finally {
|
|
227
|
+
this._active = false;
|
|
228
|
+
}
|
|
229
|
+
return { filePath: writtenPath, report };
|
|
230
|
+
}
|
|
231
|
+
/** Get the current in-memory report (snapshot). Mostly for tests. */
|
|
232
|
+
snapshot() {
|
|
233
|
+
return {
|
|
234
|
+
runId: this.makeRunId(),
|
|
235
|
+
startedAt: this._runStartIso,
|
|
236
|
+
finishedAt: new Date().toISOString(),
|
|
237
|
+
totalMs: Date.now() - this._runStartMs,
|
|
238
|
+
success: true,
|
|
239
|
+
context: { ...this._context },
|
|
240
|
+
phases: JSON.parse(JSON.stringify(this._phases)),
|
|
241
|
+
entities: Array.from(this._entities.values()).map((e) => ({ ...e, flags: { ...e.flags } })),
|
|
242
|
+
llmCalls: [...this._llmCalls],
|
|
243
|
+
counters: {
|
|
244
|
+
...this._counters,
|
|
245
|
+
spCalls: { ...this._counters.spCalls },
|
|
246
|
+
},
|
|
247
|
+
totalCostUSD: this._llmCalls.reduce((sum, c) => sum + c.costUSD, 0),
|
|
248
|
+
totalTokensIn: this._llmCalls.reduce((sum, c) => sum + c.tokensIn, 0),
|
|
249
|
+
totalTokensOut: this._llmCalls.reduce((sum, c) => sum + c.tokensOut, 0),
|
|
250
|
+
notes: [...this._notes],
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Print a human-readable summary of the completed run to stdout.
|
|
255
|
+
* Call after `endRun()` — operates on the saved report.
|
|
256
|
+
*/
|
|
257
|
+
static printSummary(report) {
|
|
258
|
+
const totalSec = report.totalMs / 1000;
|
|
259
|
+
const entCount = report.counters.entitiesProcessed ?? report.entities.length;
|
|
260
|
+
const lines = [
|
|
261
|
+
'',
|
|
262
|
+
`MJ CodeGen run ${report.startedAt} — ${formatDuration(report.totalMs)} total, ${entCount} entities`,
|
|
263
|
+
'',
|
|
264
|
+
'Top-level phases Time %',
|
|
265
|
+
'─'.repeat(52),
|
|
266
|
+
];
|
|
267
|
+
const phaseTime = CodeGenReporter.sumPhaseTime(report.phases);
|
|
268
|
+
const accounted = phaseTime;
|
|
269
|
+
function renderPhases(phases, indent, parentTotal) {
|
|
270
|
+
for (const p of phases) {
|
|
271
|
+
const pct = parentTotal > 0 ? ((p.durationMs / report.totalMs) * 100).toFixed(1) : '';
|
|
272
|
+
const time = formatDuration(p.durationMs);
|
|
273
|
+
const padPct = pct ? `${pct}%`.padStart(6) : '';
|
|
274
|
+
lines.push(`${indent}${p.name.padEnd(32)}${time.padStart(8)}${padPct}`);
|
|
275
|
+
if (p.children.length > 0) {
|
|
276
|
+
renderPhases(p.children, indent + ' ├─ ', p.durationMs);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
renderPhases(report.phases, '', report.totalMs);
|
|
281
|
+
const otherMs = report.totalMs - accounted;
|
|
282
|
+
if (otherMs > 100) {
|
|
283
|
+
const pct = ((otherMs / report.totalMs) * 100).toFixed(1);
|
|
284
|
+
lines.push(`${'other'.padEnd(32)}${formatDuration(otherMs).padStart(8)}${`${pct}%`.padStart(6)}`);
|
|
285
|
+
}
|
|
286
|
+
if (report.entities.length > 0) {
|
|
287
|
+
const top = [...report.entities].sort((a, b) => b.advancedGenerationMs - a.advancedGenerationMs).slice(0, 10);
|
|
288
|
+
lines.push('');
|
|
289
|
+
lines.push('Top 10 slowest entities (advanced generation):');
|
|
290
|
+
for (const e of top) {
|
|
291
|
+
if (e.advancedGenerationMs < 1)
|
|
292
|
+
break;
|
|
293
|
+
const cost = e.costUSD > 0 ? `$${e.costUSD.toFixed(4)}` : '';
|
|
294
|
+
const llm = e.llmCalls > 0 ? `${e.llmCalls} LLM` : '';
|
|
295
|
+
const meta = [llm, cost].filter(Boolean).join(', ');
|
|
296
|
+
lines.push(` ${e.name.padEnd(24)}${formatDuration(e.advancedGenerationMs).padStart(8)} ${meta}`);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (report.llmCalls.length > 0) {
|
|
300
|
+
lines.push('');
|
|
301
|
+
const tokensIn = report.totalTokensIn.toLocaleString();
|
|
302
|
+
const tokensOut = report.totalTokensOut.toLocaleString();
|
|
303
|
+
lines.push(`LLM totals: ${report.llmCalls.length} calls | ${tokensIn} tokens in | ${tokensOut} out | $${report.totalCostUSD.toFixed(4)}`);
|
|
304
|
+
}
|
|
305
|
+
const c = report.counters;
|
|
306
|
+
const counterParts = [];
|
|
307
|
+
if (c.entitiesNew)
|
|
308
|
+
counterParts.push(`${c.entitiesNew} new`);
|
|
309
|
+
if (c.entitiesModified)
|
|
310
|
+
counterParts.push(`${c.entitiesModified} modified`);
|
|
311
|
+
if (c.entitiesRegenerated)
|
|
312
|
+
counterParts.push(`${c.entitiesRegenerated} late-regen`);
|
|
313
|
+
if (c.sqlStatements)
|
|
314
|
+
counterParts.push(`${c.sqlStatements.toLocaleString()} SQL stmts`);
|
|
315
|
+
if (c.filesWritten)
|
|
316
|
+
counterParts.push(`${c.filesWritten.toLocaleString()} files`);
|
|
317
|
+
if (counterParts.length > 0) {
|
|
318
|
+
lines.push(`Counters: ${counterParts.join(' | ')}`);
|
|
319
|
+
}
|
|
320
|
+
lines.push('');
|
|
321
|
+
// eslint-disable-next-line no-console
|
|
322
|
+
console.log(lines.join('\n'));
|
|
323
|
+
}
|
|
324
|
+
static sumPhaseTime(phases) {
|
|
325
|
+
let total = 0;
|
|
326
|
+
for (const p of phases) {
|
|
327
|
+
total += p.durationMs;
|
|
328
|
+
}
|
|
329
|
+
return total;
|
|
330
|
+
}
|
|
331
|
+
// ------------------------------------------------------------------------
|
|
332
|
+
// Static helpers (used by `mj codegen-report` CLI and by tests)
|
|
333
|
+
// ------------------------------------------------------------------------
|
|
334
|
+
/** The directory where run JSON files are stored. */
|
|
335
|
+
static stateDir() {
|
|
336
|
+
return path.join(os.homedir(), '.mj', 'codegen-state');
|
|
337
|
+
}
|
|
338
|
+
/** List recent runs, newest first, with compact summaries. */
|
|
339
|
+
static async listRuns(limit) {
|
|
340
|
+
const dir = CodeGenReporter.stateDir();
|
|
341
|
+
let files;
|
|
342
|
+
try {
|
|
343
|
+
files = (await fs.readdir(dir)).filter((f) => f.startsWith('run-') && f.endsWith('.json'));
|
|
344
|
+
}
|
|
345
|
+
catch (err) {
|
|
346
|
+
const code = err.code;
|
|
347
|
+
if (code === 'ENOENT')
|
|
348
|
+
return [];
|
|
349
|
+
throw err;
|
|
350
|
+
}
|
|
351
|
+
const summaries = [];
|
|
352
|
+
for (const file of files) {
|
|
353
|
+
try {
|
|
354
|
+
const report = await CodeGenReporter.loadRun(file);
|
|
355
|
+
if (!report)
|
|
356
|
+
continue;
|
|
357
|
+
summaries.push({
|
|
358
|
+
runId: report.runId,
|
|
359
|
+
startedAt: report.startedAt,
|
|
360
|
+
totalMs: report.totalMs,
|
|
361
|
+
success: report.success,
|
|
362
|
+
entitiesProcessed: report.counters.entitiesProcessed ?? 0,
|
|
363
|
+
llmCalls: report.llmCalls.length,
|
|
364
|
+
totalCostUSD: report.totalCostUSD,
|
|
365
|
+
filePath: path.join(dir, file),
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
catch {
|
|
369
|
+
// Skip malformed files silently
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
summaries.sort((a, b) => b.startedAt.localeCompare(a.startedAt));
|
|
373
|
+
return typeof limit === 'number' ? summaries.slice(0, limit) : summaries;
|
|
374
|
+
}
|
|
375
|
+
/** Load a single run by file name OR run id. Returns null if not found. */
|
|
376
|
+
static async loadRun(runIdOrFile) {
|
|
377
|
+
const dir = CodeGenReporter.stateDir();
|
|
378
|
+
const file = runIdOrFile.endsWith('.json') ? runIdOrFile : `run-${runIdOrFile}.json`;
|
|
379
|
+
const full = path.join(dir, file);
|
|
380
|
+
try {
|
|
381
|
+
const raw = await fs.readFile(full, 'utf8');
|
|
382
|
+
return JSON.parse(raw);
|
|
383
|
+
}
|
|
384
|
+
catch (err) {
|
|
385
|
+
const code = err.code;
|
|
386
|
+
if (code === 'ENOENT')
|
|
387
|
+
return null;
|
|
388
|
+
throw err;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Prune `~/.mj/codegen-state/` to the most recent MAX_RETAINED_RUNS files.
|
|
393
|
+
* Non-fatal on errors.
|
|
394
|
+
*/
|
|
395
|
+
static async pruneOldRuns() {
|
|
396
|
+
try {
|
|
397
|
+
const dir = CodeGenReporter.stateDir();
|
|
398
|
+
const files = (await fs.readdir(dir))
|
|
399
|
+
.filter((f) => f.startsWith('run-') && f.endsWith('.json'))
|
|
400
|
+
.sort()
|
|
401
|
+
.reverse();
|
|
402
|
+
const toDelete = files.slice(MAX_RETAINED_RUNS);
|
|
403
|
+
await Promise.all(toDelete.map((f) => fs.unlink(path.join(dir, f)).catch((err) => {
|
|
404
|
+
// eslint-disable-next-line no-console
|
|
405
|
+
console.warn(`[codegen-reporter] Failed to prune ${f}: ${err.message}`);
|
|
406
|
+
})));
|
|
407
|
+
}
|
|
408
|
+
catch {
|
|
409
|
+
// Directory may not exist yet — safe to ignore.
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
// ------------------------------------------------------------------------
|
|
413
|
+
// Internals
|
|
414
|
+
// ------------------------------------------------------------------------
|
|
415
|
+
getOrCreateEntity(name) {
|
|
416
|
+
let entry = this._entities.get(name);
|
|
417
|
+
if (!entry) {
|
|
418
|
+
entry = {
|
|
419
|
+
name,
|
|
420
|
+
totalMs: 0,
|
|
421
|
+
advancedGenerationMs: 0,
|
|
422
|
+
llmCalls: 0,
|
|
423
|
+
tokensIn: 0,
|
|
424
|
+
tokensOut: 0,
|
|
425
|
+
costUSD: 0,
|
|
426
|
+
flags: { new: false, modified: false, regenerated: false },
|
|
427
|
+
};
|
|
428
|
+
this._entities.set(name, entry);
|
|
429
|
+
}
|
|
430
|
+
return entry;
|
|
431
|
+
}
|
|
432
|
+
emptyCounters() {
|
|
433
|
+
return {
|
|
434
|
+
entitiesProcessed: 0,
|
|
435
|
+
entitiesNew: 0,
|
|
436
|
+
entitiesModified: 0,
|
|
437
|
+
entitiesRegenerated: 0,
|
|
438
|
+
sqlStatements: 0,
|
|
439
|
+
filesWritten: 0,
|
|
440
|
+
spCalls: {},
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
makeRunId() {
|
|
444
|
+
// Filename-safe ISO: replace colons and dots so the string is valid on
|
|
445
|
+
// all common file systems. Example: "2026-04-15T19-42-03-104Z".
|
|
446
|
+
return this._runStartIso.replace(/[:.]/g, '-');
|
|
447
|
+
}
|
|
448
|
+
/**
|
|
449
|
+
* Absolute start time of a phase (ms since epoch). The phase's own
|
|
450
|
+
* startMs is stored relative to its parent (or run start), so we have
|
|
451
|
+
* to walk up the stack to get an absolute.
|
|
452
|
+
*/
|
|
453
|
+
phaseStartAbs(phase) {
|
|
454
|
+
let abs = this._runStartMs;
|
|
455
|
+
for (const s of this._phaseStack) {
|
|
456
|
+
abs += s.startMs;
|
|
457
|
+
if (s === phase)
|
|
458
|
+
break;
|
|
459
|
+
}
|
|
460
|
+
return abs;
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
// ----------------------------------------------------------------------------
|
|
464
|
+
// Convenience wrappers (mirrors status_logging.ts style)
|
|
465
|
+
// ----------------------------------------------------------------------------
|
|
466
|
+
/** Shortcut: wrap a phase using the singleton. */
|
|
467
|
+
export function reportPhase(name, fn) {
|
|
468
|
+
return CodeGenReporter.Instance.phase(name, fn);
|
|
469
|
+
}
|
|
470
|
+
/** Shortcut: wrap a per-entity phase using the singleton. */
|
|
471
|
+
export function reportEntityPhase(entityName, phaseName, fn) {
|
|
472
|
+
return CodeGenReporter.Instance.entityPhase(entityName, phaseName, fn);
|
|
473
|
+
}
|
|
474
|
+
/** Shortcut: increment a counter using the singleton. */
|
|
475
|
+
export function reportCounter(name, delta = 1) {
|
|
476
|
+
CodeGenReporter.Instance.counter(name, delta);
|
|
477
|
+
}
|
|
478
|
+
/** Shortcut: set a context mark using the singleton. */
|
|
479
|
+
export function reportMark(key, value) {
|
|
480
|
+
CodeGenReporter.Instance.mark(key, value);
|
|
481
|
+
}
|
|
482
|
+
function formatDuration(ms) {
|
|
483
|
+
if (ms < 1000)
|
|
484
|
+
return `${ms.toFixed(0)}ms`;
|
|
485
|
+
const sec = ms / 1000;
|
|
486
|
+
if (sec < 60)
|
|
487
|
+
return `${sec.toFixed(1)}s`;
|
|
488
|
+
const m = Math.floor(sec / 60);
|
|
489
|
+
const s = Math.round(sec % 60);
|
|
490
|
+
return `${m}m ${s}s`;
|
|
491
|
+
}
|
|
492
|
+
//# sourceMappingURL=codegen-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"codegen-reporter.js","sourceRoot":"","sources":["../../src/Misc/codegen-reporter.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"createNewUser.d.ts","sourceRoot":"","sources":["../../src/Misc/createNewUser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMhD;;GAEG;AACH,qBAAa,iBAAiB;IACb,aAAa,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;KAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"createNewUser.d.ts","sourceRoot":"","sources":["../../src/Misc/createNewUser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAMhD;;GAEG;AACH,qBAAa,iBAAiB;IACb,aAAa,CAAC,YAAY,EAAE,YAAY,GAAG,OAAO,CAAC;QAAC,OAAO,EAAE,OAAO,CAAC;QAAC,OAAO,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,SAAS,GAAG,OAAO,GAAG,SAAS,CAAA;KAAC,CAAC;CA2JlJ"}
|
|
@@ -31,8 +31,16 @@ export class CreateNewUserBase {
|
|
|
31
31
|
user.Email = newUserSetup.Email;
|
|
32
32
|
user.Type = 'Owner';
|
|
33
33
|
user.IsActive = true;
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
// Create the user and all of its role/application/app-entity records atomically.
|
|
35
|
+
// If any Save fails partway through, the whole provisioning rolls back so we never
|
|
36
|
+
// leave a half-created user with partial roles/applications behind.
|
|
37
|
+
const provider = Metadata.Provider;
|
|
38
|
+
await provider.BeginTransaction();
|
|
39
|
+
try {
|
|
40
|
+
if (!await user.Save()) {
|
|
41
|
+
throw new Error("Failed to save new user: " + newUserSetup.Email);
|
|
42
|
+
}
|
|
43
|
+
// User Roles
|
|
36
44
|
for (let i = 0; i < newUserSetup.Roles.length; i++) {
|
|
37
45
|
const roleName = newUserSetup.Roles[i];
|
|
38
46
|
const roleID = md.Roles.find(r => r.Name === roleName)?.ID;
|
|
@@ -44,14 +52,12 @@ export class CreateNewUserBase {
|
|
|
44
52
|
userRole.NewRecord();
|
|
45
53
|
userRole.UserID = user.ID;
|
|
46
54
|
userRole.RoleID = roleID;
|
|
47
|
-
if (await userRole.Save()) {
|
|
48
|
-
|
|
49
|
-
}
|
|
50
|
-
else {
|
|
51
|
-
logError(" Failed to create User Role: " + roleName);
|
|
55
|
+
if (!await userRole.Save()) {
|
|
56
|
+
throw new Error(`Failed to create User Role '${roleName}': ${userRole.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
52
57
|
}
|
|
58
|
+
logStatus(" Created User Role: " + roleName);
|
|
53
59
|
}
|
|
54
|
-
//
|
|
60
|
+
// User Applications + nested User Application Entities
|
|
55
61
|
if (newUserSetup.CreateUserApplicationRecords) {
|
|
56
62
|
logStatus("Creating User Applications for new user: " + user.Name);
|
|
57
63
|
for (const appName of newUserSetup.UserApplications) {
|
|
@@ -66,40 +72,35 @@ export class CreateNewUserBase {
|
|
|
66
72
|
userApplication.UserID = user.ID;
|
|
67
73
|
userApplication.ApplicationID = application.ID;
|
|
68
74
|
userApplication.IsActive = true;
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
logStatus(`Created User Application ${appName} for new user ${user.Name}`);
|
|
72
|
-
//now create a MJUserApplicationEntity records for each entity in the application
|
|
73
|
-
const rv = new RunView();
|
|
74
|
-
const rvResult = await rv.RunView({
|
|
75
|
-
EntityName: 'MJ: Application Entities',
|
|
76
|
-
ExtraFilter: `ApplicationID = '${application.ID}' and DefaultForNewUser = 1`,
|
|
77
|
-
}, currentUser);
|
|
78
|
-
if (!rvResult.Success) {
|
|
79
|
-
LogError(`Failed to load Application Entities for Application ${appName} for new user ${user.Name}:`, undefined, rvResult.ErrorMessage);
|
|
80
|
-
continue;
|
|
81
|
-
}
|
|
82
|
-
LogStatus(`Creating ${rvResult.Results.length} User Application Entities for User Application ${appName} for new user ${user.Name}`);
|
|
83
|
-
for (const [index, appEntity] of rvResult.Results.entries()) {
|
|
84
|
-
const userAppEntity = await md.GetEntityObject('MJ: User Application Entities', currentUser);
|
|
85
|
-
userAppEntity.NewRecord();
|
|
86
|
-
userAppEntity.UserApplicationID = userApplication.ID;
|
|
87
|
-
userAppEntity.EntityID = appEntity.EntityID;
|
|
88
|
-
userAppEntity.Sequence = index;
|
|
89
|
-
const userAppEntitySaveResult = await userAppEntity.Save();
|
|
90
|
-
if (userAppEntitySaveResult) {
|
|
91
|
-
LogStatus(`Created User Application Entity ${appEntity.Entity} for new user ${user.Name}`);
|
|
92
|
-
}
|
|
93
|
-
else {
|
|
94
|
-
LogError(`Failed to create User Application Entity for new user ${user.Name}:`, undefined, userAppEntity.LatestResult);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
75
|
+
if (!await userApplication.Save()) {
|
|
76
|
+
throw new Error(`Failed to create User Application ${appName} for new user ${user.Name}: ${userApplication.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
97
77
|
}
|
|
98
|
-
|
|
99
|
-
|
|
78
|
+
logStatus(`Created User Application ${appName} for new user ${user.Name}`);
|
|
79
|
+
//now create MJUserApplicationEntity records for each entity in the application
|
|
80
|
+
const rv = new RunView();
|
|
81
|
+
const rvResult = await rv.RunView({
|
|
82
|
+
EntityName: 'MJ: Application Entities',
|
|
83
|
+
ExtraFilter: `ApplicationID = '${application.ID}' and DefaultForNewUser = 1`,
|
|
84
|
+
}, currentUser);
|
|
85
|
+
if (!rvResult.Success) {
|
|
86
|
+
LogError(`Failed to load Application Entities for Application ${appName} for new user ${user.Name}:`, undefined, rvResult.ErrorMessage);
|
|
87
|
+
continue;
|
|
88
|
+
}
|
|
89
|
+
LogStatus(`Creating ${rvResult.Results.length} User Application Entities for User Application ${appName} for new user ${user.Name}`);
|
|
90
|
+
for (const [index, appEntity] of rvResult.Results.entries()) {
|
|
91
|
+
const userAppEntity = await md.GetEntityObject('MJ: User Application Entities', currentUser);
|
|
92
|
+
userAppEntity.NewRecord();
|
|
93
|
+
userAppEntity.UserApplicationID = userApplication.ID;
|
|
94
|
+
userAppEntity.EntityID = appEntity.EntityID;
|
|
95
|
+
userAppEntity.Sequence = index;
|
|
96
|
+
if (!await userAppEntity.Save()) {
|
|
97
|
+
throw new Error(`Failed to create User Application Entity for new user ${user.Name}: ${userAppEntity.LatestResult?.CompleteMessage ?? 'unknown error'}`);
|
|
98
|
+
}
|
|
99
|
+
LogStatus(`Created User Application Entity ${appEntity.Entity} for new user ${user.Name}`);
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
}
|
|
103
|
+
await provider.CommitTransaction();
|
|
103
104
|
logStatus("Finished creating new user: " + newUserSetup.Email);
|
|
104
105
|
return {
|
|
105
106
|
Success: true,
|
|
@@ -107,11 +108,11 @@ export class CreateNewUserBase {
|
|
|
107
108
|
Severity: undefined
|
|
108
109
|
};
|
|
109
110
|
}
|
|
110
|
-
|
|
111
|
-
|
|
111
|
+
catch (txErr) {
|
|
112
|
+
await provider.RollbackTransaction();
|
|
112
113
|
return {
|
|
113
114
|
Success: false,
|
|
114
|
-
Message:
|
|
115
|
+
Message: txErr instanceof Error ? txErr.message : String(txErr),
|
|
115
116
|
Severity: 'error'
|
|
116
117
|
};
|
|
117
118
|
}
|