@mindstudio-ai/local-model-tunnel 0.5.25 → 0.5.27

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.
@@ -88,6 +88,7 @@ function deleteLocalInterfacePath(key) {
88
88
 
89
89
  // src/dev/logging/logger.ts
90
90
  import fs from "fs";
91
+ import { join } from "path";
91
92
  var LEVELS = {
92
93
  error: 0,
93
94
  warn: 1,
@@ -97,31 +98,28 @@ var LEVELS = {
97
98
  var currentLevel = LEVELS.error;
98
99
  var writeFn = () => {
99
100
  };
100
- function timestamp() {
101
- return (/* @__PURE__ */ new Date()).toISOString();
102
- }
103
- function write(level, msg, data) {
101
+ function write(level, module, msg, data) {
104
102
  if (LEVELS[level] > currentLevel) {
105
103
  return;
106
104
  }
107
- const parts = [`[${timestamp()}]`, level.toUpperCase().padEnd(5), msg];
105
+ const entry = { ts: Date.now(), level, module, msg };
108
106
  if (data) {
109
- parts.push(JSON.stringify(data));
107
+ Object.assign(entry, data);
110
108
  }
111
- writeFn(parts.join(" "));
109
+ writeFn(JSON.stringify(entry));
112
110
  }
113
111
  var log = {
114
- error(msg, data) {
115
- write("error", msg, data);
112
+ error(module, msg, data) {
113
+ write("error", module, msg, data);
116
114
  },
117
- warn(msg, data) {
118
- write("warn", msg, data);
115
+ warn(module, msg, data) {
116
+ write("warn", module, msg, data);
119
117
  },
120
- info(msg, data) {
121
- write("info", msg, data);
118
+ info(module, msg, data) {
119
+ write("info", module, msg, data);
122
120
  },
123
- debug(msg, data) {
124
- write("debug", msg, data);
121
+ debug(module, msg, data) {
122
+ write("debug", module, msg, data);
125
123
  }
126
124
  };
127
125
  function initLoggerHeadless(level = "info") {
@@ -136,7 +134,9 @@ function initLoggerInteractive(level = "error") {
136
134
  writeFn = (line) => {
137
135
  try {
138
136
  if (fd === null) {
139
- fd = fs.openSync(".mindstudio-dev.log", "a");
137
+ const logsDir = join(process.cwd(), ".logs");
138
+ fs.mkdirSync(logsDir, { recursive: true });
139
+ fd = fs.openSync(join(logsDir, "tunnel.ndjson"), "a");
140
140
  }
141
141
  fs.writeSync(fd, line + "\n");
142
142
  } catch {
@@ -162,7 +162,8 @@ function basePath(appId) {
162
162
  }
163
163
  async function apiRequest(method, url, headers, body) {
164
164
  const start = Date.now();
165
- const logTag = `${method} ${url.replace(getApiBaseUrl(), "")}`;
165
+ const httpMethod = method;
166
+ const path2 = url.replace(getApiBaseUrl(), "").replace(/^\/_internal\/v2\/apps\/[^/]+\/dev/, "");
166
167
  const response = await fetch(url, {
167
168
  method,
168
169
  headers,
@@ -170,16 +171,16 @@ async function apiRequest(method, url, headers, body) {
170
171
  });
171
172
  const duration = Date.now() - start;
172
173
  if (response.status === 204) {
173
- log.debug(`api ${logTag} \u2192 204 (${duration}ms)`);
174
+ log.debug("api", "Request complete", { method: httpMethod, path: path2, status: 204, duration });
174
175
  return null;
175
176
  }
176
177
  if (!response.ok) {
177
178
  const error = await response.text();
178
- log.error(`api ${logTag} \u2192 ${response.status} (${duration}ms)`, { error });
179
- throw new ApiError(`${logTag} failed: ${response.status} ${error}`, response.status);
179
+ log.error("api", "Request failed", { method: httpMethod, path: path2, status: response.status, duration, error });
180
+ throw new ApiError(`${httpMethod} ${path2} failed: ${response.status} ${error}`, response.status);
180
181
  }
181
182
  const data = await response.json();
182
- log.info(`api ${logTag} \u2192 ${response.status} (${duration}ms)`);
183
+ log.info("api", "Request complete", { method: httpMethod, path: path2, status: response.status, duration });
183
184
  return data;
184
185
  }
185
186
  async function startDevSession(appId, opts) {
@@ -276,7 +277,7 @@ var DevPollError = class extends Error {
276
277
 
277
278
  // src/dev/logging/ndjson-log.ts
278
279
  import fs2 from "fs";
279
- import { join } from "path";
280
+ import { join as join2 } from "path";
280
281
  var NdjsonLog = class {
281
282
  constructor(filename, maxLines = 500, keepLines = 300, maxBytes = 2 * 1024 * 1024) {
282
283
  this.filename = filename;
@@ -291,9 +292,9 @@ var NdjsonLog = class {
291
292
  init(projectRoot) {
292
293
  this.close();
293
294
  try {
294
- const logsDir = join(projectRoot, ".logs");
295
+ const logsDir = join2(projectRoot, ".logs");
295
296
  fs2.mkdirSync(logsDir, { recursive: true });
296
- this.logPath = join(logsDir, this.filename);
297
+ this.logPath = join2(logsDir, this.filename);
297
298
  if (fs2.existsSync(this.logPath)) {
298
299
  const content = fs2.readFileSync(this.logPath, "utf-8");
299
300
  this.lineCount = content.split("\n").filter((l) => l.trim()).length;
@@ -301,12 +302,12 @@ var NdjsonLog = class {
301
302
  this.lineCount = 0;
302
303
  }
303
304
  this.fd = fs2.openSync(this.logPath, "a");
304
- log.info(`${this.filename} log initialized`, {
305
+ log.debug("logging", `${this.filename} log initialized`, {
305
306
  path: this.logPath,
306
307
  existingEntries: this.lineCount
307
308
  });
308
309
  } catch (err) {
309
- log.warn(`Failed to initialize ${this.filename} log`, {
310
+ log.warn("logging", `Failed to initialize ${this.filename} log`, {
310
311
  error: err instanceof Error ? err.message : String(err)
311
312
  });
312
313
  this.fd = null;
@@ -320,10 +321,7 @@ var NdjsonLog = class {
320
321
  fs2.writeSync(this.fd, line);
321
322
  this.lineCount++;
322
323
  this.maybeRotate();
323
- } catch (err) {
324
- log.debug(`Failed to write ${this.filename} log entry`, {
325
- error: err instanceof Error ? err.message : String(err)
326
- });
324
+ } catch {
327
325
  }
328
326
  }
329
327
  close() {
@@ -355,11 +353,7 @@ var NdjsonLog = class {
355
353
  fs2.writeFileSync(this.logPath, kept.join("\n") + "\n", "utf-8");
356
354
  this.fd = fs2.openSync(this.logPath, "a");
357
355
  this.lineCount = kept.length;
358
- log.debug(`${this.filename} log rotated`, { kept: this.lineCount });
359
- } catch (err) {
360
- log.debug(`${this.filename} log rotation failed`, {
361
- error: err instanceof Error ? err.message : String(err)
362
- });
356
+ } catch {
363
357
  } finally {
364
358
  this.rotating = false;
365
359
  }
@@ -373,8 +367,11 @@ function initRequestLog(projectRoot) {
373
367
  }
374
368
  function logMethodExecution(entry) {
375
369
  ndjsonLog.append({
370
+ ts: Date.now(),
371
+ level: "info",
372
+ module: "execution",
373
+ msg: entry.result.success ? "Method complete" : "Method failed",
376
374
  type: "method",
377
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
378
375
  requestId: entry.requestId,
379
376
  sessionId: entry.sessionId,
380
377
  method: entry.methodExport,
@@ -393,8 +390,11 @@ function logMethodExecution(entry) {
393
390
  }
394
391
  function logScenarioExecution(entry) {
395
392
  ndjsonLog.append({
393
+ ts: Date.now(),
394
+ level: "info",
395
+ module: "execution",
396
+ msg: entry.result?.success ?? false ? "Scenario complete" : "Scenario failed",
396
397
  type: "scenario",
397
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
398
398
  sessionId: entry.sessionId,
399
399
  scenario: {
400
400
  id: entry.scenario.id,
@@ -480,7 +480,7 @@ var devRequestEvents = new DevEventEmitter();
480
480
  // src/dev/execution/transpiler.ts
481
481
  import { unlink, mkdir, readdir } from "fs/promises";
482
482
  import { existsSync } from "fs";
483
- import { resolve, dirname, basename, join as join2 } from "path";
483
+ import { resolve, dirname, basename, join as join3 } from "path";
484
484
  import { build } from "esbuild";
485
485
  var Transpiler = class {
486
486
  projectRoot;
@@ -506,18 +506,16 @@ var Transpiler = class {
506
506
  const start = Date.now();
507
507
  const absolutePath = resolve(this.projectRoot, methodPath);
508
508
  const name = basename(absolutePath).replace(/\.[^.]+$/, "");
509
- log.debug("Transpiling method", { methodPath });
510
509
  const nodeModulesDir = findNearestNodeModules(dirname(absolutePath));
511
510
  if (!nodeModulesDir) {
512
- log.error("Cannot find node_modules for method", { methodPath, searchStart: dirname(absolutePath) });
511
+ log.error("transpiler", "Cannot find node_modules for method", { methodPath, searchStart: dirname(absolutePath) });
513
512
  throw new Error(
514
513
  `No node_modules found near ${methodPath}. Run npm install first.`
515
514
  );
516
515
  }
517
- log.debug("Found node_modules", { path: nodeModulesDir });
518
- const outDir = join2(nodeModulesDir, ".cache", "mindstudio-dev");
516
+ const outDir = join3(nodeModulesDir, ".cache", "mindstudio-dev");
519
517
  await mkdir(outDir, { recursive: true });
520
- const outfile = join2(outDir, `${name}.__ms_dev__.mjs`);
518
+ const outfile = join3(outDir, `${name}.__ms_dev__.mjs`);
521
519
  await build({
522
520
  entryPoints: [absolutePath],
523
521
  bundle: true,
@@ -530,14 +528,13 @@ var Transpiler = class {
530
528
  logLevel: "silent"
531
529
  });
532
530
  this.outputFiles.add(outfile);
533
- log.info(`Method transpiled in ${Date.now() - start}ms`, { methodPath, outfile });
531
+ log.info("transpiler", "Method transpiled", { duration: Date.now() - start, methodPath, outfile });
534
532
  return outfile;
535
533
  }
536
534
  /**
537
535
  * Clean up all transpiled output files.
538
536
  */
539
537
  async cleanup() {
540
- log.debug("Cleaning up transpiled files", { fileCount: this.outputFiles.size });
541
538
  for (const file of this.outputFiles) {
542
539
  await unlink(file).catch(() => {
543
540
  });
@@ -549,11 +546,10 @@ async function removeOrphanedDevFiles(dir) {
549
546
  const entries = await readdir(dir, { withFileTypes: true });
550
547
  for (const entry of entries) {
551
548
  if (entry.name === "node_modules" || entry.name === ".git") continue;
552
- const fullPath = join2(dir, entry.name);
549
+ const fullPath = join3(dir, entry.name);
553
550
  if (entry.isDirectory()) {
554
551
  await removeOrphanedDevFiles(fullPath);
555
552
  } else if (entry.name.endsWith(".__ms_dev__.mjs")) {
556
- log.debug("Removing orphaned transpiled file", { path: fullPath });
557
553
  await unlink(fullPath).catch(() => {
558
554
  });
559
555
  }
@@ -562,7 +558,7 @@ async function removeOrphanedDevFiles(dir) {
562
558
  function findNearestNodeModules(startDir) {
563
559
  let dir = startDir;
564
560
  while (true) {
565
- const candidate = join2(dir, "node_modules");
561
+ const candidate = join3(dir, "node_modules");
566
562
  if (existsSync(candidate)) {
567
563
  return candidate;
568
564
  }
@@ -576,7 +572,7 @@ function findNearestNodeModules(startDir) {
576
572
  // src/dev/execution/executor.ts
577
573
  import { fork } from "child_process";
578
574
  import { writeFile, unlink as unlink2 } from "fs/promises";
579
- import { join as join3 } from "path";
575
+ import { join as join4 } from "path";
580
576
  import { tmpdir } from "os";
581
577
  import { randomBytes } from "crypto";
582
578
  var EXECUTION_TIMEOUT_MS = 30 * 60 * 1e3;
@@ -675,6 +671,10 @@ async function ensureWorker(projectRoot) {
675
671
  if (worker?.connected && workerProjectRoot === projectRoot) {
676
672
  return worker;
677
673
  }
674
+ if (worker || workerProjectRoot) {
675
+ const reason = workerProjectRoot !== projectRoot ? "project-root-changed" : "disconnected";
676
+ log.info("executor", "Respawning worker process", { reason });
677
+ }
678
678
  if (worker) {
679
679
  worker.removeAllListeners();
680
680
  worker.kill();
@@ -685,14 +685,14 @@ async function ensureWorker(projectRoot) {
685
685
  });
686
686
  workerScriptPath = null;
687
687
  }
688
- const scriptPath = join3(
688
+ const scriptPath = join4(
689
689
  tmpdir(),
690
690
  `ms-dev-worker-${randomBytes(4).toString("hex")}.mjs`
691
691
  );
692
692
  await writeFile(scriptPath, buildWorkerScript(), "utf-8");
693
693
  workerScriptPath = scriptPath;
694
694
  workerProjectRoot = projectRoot;
695
- log.debug("Spawning method execution process", { cwd: projectRoot, scriptPath });
695
+ log.debug("executor", "Spawning method execution process", { cwd: projectRoot, scriptPath });
696
696
  const child = fork(scriptPath, [], {
697
697
  cwd: projectRoot,
698
698
  stdio: ["ignore", "pipe", "pipe", "ipc"],
@@ -718,7 +718,7 @@ async function ensureWorker(projectRoot) {
718
718
  req.resolve(msg);
719
719
  });
720
720
  child.on("exit", (code) => {
721
- log.warn("Method execution process exited unexpectedly", { code });
721
+ log.warn("executor", "Method execution process exited unexpectedly", { code });
722
722
  for (const [id, req] of pending) {
723
723
  clearTimeout(req.timer);
724
724
  req.resolve({ success: false, error: { message: `Worker process exited with code ${code}` } });
@@ -728,23 +728,33 @@ async function ensureWorker(projectRoot) {
728
728
  });
729
729
  child.stderr?.on("data", (chunk) => {
730
730
  const text = chunk.toString().trim();
731
- if (text) log.warn("Method process stderr", { text: text.slice(0, 500) });
731
+ if (text) log.warn("executor", "Method process stderr", { text: text.slice(0, 500) });
732
732
  });
733
733
  worker = child;
734
- log.info("Method execution process ready", { pid: child.pid });
734
+ log.info("executor", "Method execution process ready", { pid: child.pid });
735
735
  return child;
736
736
  }
737
- async function executeMethod(opts) {
737
+ var queueTail = Promise.resolve();
738
+ function enqueue(fn) {
739
+ const task = queueTail.then(fn, fn);
740
+ queueTail = task.catch(() => {
741
+ });
742
+ return task;
743
+ }
744
+ function executeMethod(opts) {
745
+ return enqueue(() => executeMethodInWorker(opts));
746
+ }
747
+ async function executeMethodInWorker(opts) {
738
748
  const w = await ensureWorker(opts.projectRoot);
739
749
  const id = randomBytes(8).toString("hex");
740
- log.debug("Sending method to execution process", { id, methodExport: opts.methodExport });
750
+ log.debug("executor", "Sending method to execution process", { id, methodExport: opts.methodExport });
741
751
  return new Promise((resolve2) => {
742
752
  const timer = setTimeout(() => {
743
753
  pending.delete(id);
744
- log.warn("Method execution timed out", { id, methodExport: opts.methodExport });
754
+ log.warn("executor", "Method execution timed out", { id, methodExport: opts.methodExport });
745
755
  resolve2({
746
756
  success: false,
747
- error: { message: "Method execution timed out after 30s" }
757
+ error: { message: "Method execution timed out after 30m" }
748
758
  });
749
759
  }, EXECUTION_TIMEOUT_MS);
750
760
  pending.set(id, { resolve: resolve2, timer });
@@ -777,6 +787,7 @@ async function cleanupWorker() {
777
787
  clearTimeout(req.timer);
778
788
  }
779
789
  pending.clear();
790
+ queueTail = Promise.resolve();
780
791
  }
781
792
 
782
793
  // src/api.ts
@@ -980,6 +991,7 @@ var DevRunner = class {
980
991
  hadConnectionWarning = false;
981
992
  proxyUrl;
982
993
  proxy = null;
994
+ roleOverride = null;
983
995
  // proxyUrl is sent on every poll request so the platform dashboard can
984
996
  // show the developer's preview URL. Also included in the start request
985
997
  // so the dashboard sees it immediately without waiting for the first poll.
@@ -994,13 +1006,13 @@ var DevRunner = class {
994
1006
  if (this.isRunning) {
995
1007
  throw new Error("DevRunner is already running");
996
1008
  }
997
- log.info("Dev session starting", { appId: this.appId, branch: this.startOpts.branch });
1009
+ log.info("runner", "Dev session starting", { appId: this.appId, branch: this.startOpts.branch });
998
1010
  const session = await startDevSession(this.appId, this.startOpts);
999
1011
  this.session = session;
1000
1012
  this.transpiler = new Transpiler(this.projectRoot);
1001
1013
  this.isRunning = true;
1002
1014
  this.backoffMs = 1e3;
1003
- log.info("Dev session started", { sessionId: session.sessionId, branch: session.branch });
1015
+ log.info("runner", "Dev session started", { sessionId: session.sessionId, branch: session.branch });
1004
1016
  return session;
1005
1017
  }
1006
1018
  // Begin polling for platform method requests. Call this after all
@@ -1010,16 +1022,17 @@ var DevRunner = class {
1010
1022
  this.pollLoop();
1011
1023
  }
1012
1024
  async stop() {
1013
- log.info("Dev session stopping");
1025
+ log.info("runner", "Dev session stopping");
1014
1026
  this.isRunning = false;
1015
1027
  if (this.session) {
1016
1028
  try {
1017
1029
  await stopDevSession(this.appId, this.session.sessionId);
1018
1030
  } catch (err) {
1019
- log.warn("Failed to stop dev session cleanly", { error: err instanceof Error ? err.message : String(err) });
1031
+ log.warn("runner", "Failed to stop dev session cleanly", { error: err instanceof Error ? err.message : String(err) });
1020
1032
  }
1021
1033
  this.session = null;
1022
1034
  }
1035
+ this.roleOverride = null;
1023
1036
  await cleanupWorker();
1024
1037
  if (this.transpiler) {
1025
1038
  await this.transpiler.cleanup();
@@ -1032,15 +1045,17 @@ var DevRunner = class {
1032
1045
  // Set role override for subsequent method executions.
1033
1046
  async setImpersonation(roles) {
1034
1047
  if (!this.session) return;
1035
- log.info("Setting role override", { roles });
1048
+ log.info("runner", "Setting role override", { roles });
1036
1049
  await impersonate(this.appId, this.session.sessionId, roles);
1050
+ this.roleOverride = roles;
1037
1051
  await this.refreshClientContext();
1038
1052
  }
1039
1053
  // Clear role override — revert to session's default roles.
1040
1054
  async clearImpersonation() {
1041
1055
  if (!this.session) return;
1042
- log.info("Clearing role override");
1056
+ log.info("runner", "Clearing role override");
1043
1057
  await impersonate(this.appId, this.session.sessionId, null);
1058
+ this.roleOverride = null;
1044
1059
  await this.refreshClientContext();
1045
1060
  }
1046
1061
  // Fetch fresh clientContext from platform and update the proxy.
@@ -1052,7 +1067,7 @@ var DevRunner = class {
1052
1067
  this.session.clientContext = context;
1053
1068
  this.proxy.updateClientContext(context);
1054
1069
  } catch (err) {
1055
- log.warn("Failed to refresh session context after role change", { error: err instanceof Error ? err.message : String(err) });
1070
+ log.warn("runner", "Failed to refresh session context after role change", { error: err instanceof Error ? err.message : String(err) });
1056
1071
  }
1057
1072
  }
1058
1073
  // Run a method directly (not via poll loop). Used by headless stdin commands
@@ -1063,15 +1078,22 @@ var DevRunner = class {
1063
1078
  }
1064
1079
  const requestId = randomBytes2(8).toString("hex");
1065
1080
  const startTime = Date.now();
1066
- log.info("Method received (direct)", { requestId, method: opts.methodExport });
1081
+ log.info("runner", "Method received", { requestId, method: opts.methodExport, source: "direct", sessionId: this.session.sessionId });
1067
1082
  try {
1068
1083
  const authorizationToken = await fetchCallbackToken(this.appId, this.session.sessionId);
1069
1084
  const transpiledPath = await this.transpiler.transpile(opts.methodPath);
1085
+ const auth = this.roleOverride ? {
1086
+ userId: this.session.auth.userId,
1087
+ roleAssignments: this.roleOverride.map((roleName) => ({
1088
+ userId: this.session.auth.userId,
1089
+ roleName
1090
+ }))
1091
+ } : this.session.auth;
1070
1092
  const result = await executeMethod({
1071
1093
  transpiledPath,
1072
1094
  methodExport: opts.methodExport,
1073
1095
  input: opts.input,
1074
- auth: this.session.auth,
1096
+ auth,
1075
1097
  databases: this.session.databases,
1076
1098
  authorizationToken,
1077
1099
  apiBaseUrl: getApiBaseUrl(),
@@ -1079,13 +1101,14 @@ var DevRunner = class {
1079
1101
  });
1080
1102
  const duration = Date.now() - startTime;
1081
1103
  if (result.success) {
1082
- log.info("Method complete", { requestId, method: opts.methodExport, duration });
1104
+ log.info("runner", "Method complete", { requestId, method: opts.methodExport, duration, sessionId: this.session.sessionId });
1083
1105
  } else {
1084
- log.warn("Method failed", {
1106
+ log.warn("runner", "Method failed", {
1085
1107
  requestId,
1086
1108
  method: opts.methodExport,
1087
1109
  duration,
1088
- error: result.error ? formatErrorForDisplay(result.error) : void 0
1110
+ error: result.error ? formatErrorForDisplay(result.error) : void 0,
1111
+ sessionId: this.session.sessionId
1089
1112
  });
1090
1113
  }
1091
1114
  logMethodExecution({
@@ -1109,7 +1132,7 @@ var DevRunner = class {
1109
1132
  } catch (err) {
1110
1133
  const message = err instanceof Error ? err.message : "Unknown error";
1111
1134
  const duration = Date.now() - startTime;
1112
- log.error("Method error", { requestId, method: opts.methodExport, duration, error: message });
1135
+ log.error("runner", "Method execution error", { requestId, method: opts.methodExport, duration, error: message, sessionId: this.session.sessionId });
1113
1136
  logMethodExecution({
1114
1137
  requestId,
1115
1138
  sessionId: this.session.sessionId,
@@ -1132,15 +1155,15 @@ var DevRunner = class {
1132
1155
  }
1133
1156
  const startTime = Date.now();
1134
1157
  const scenarioName = scenario.name ?? scenario.export;
1135
- log.info("Scenario starting", { id: scenario.id, name: scenarioName });
1158
+ log.info("runner", "Scenario starting", { id: scenario.id, name: scenarioName });
1136
1159
  try {
1137
- log.info("Resetting database for scenario");
1160
+ log.debug("runner", "Resetting database for scenario");
1138
1161
  const databases = await resetDevDatabase(this.appId, this.session.sessionId, "truncate");
1139
1162
  this.session.databases = databases;
1140
- log.info("Transpiling scenario", { path: scenario.path });
1163
+ log.debug("runner", "Transpiling scenario", { path: scenario.path });
1141
1164
  const transpiledPath = await this.transpiler.transpile(scenario.path);
1142
1165
  const authorizationToken = await fetchCallbackToken(this.appId, this.session.sessionId);
1143
- log.info("Running scenario seed function", { export: scenario.export });
1166
+ log.debug("runner", "Running scenario seed function", { export: scenario.export });
1144
1167
  const result = await executeMethod({
1145
1168
  transpiledPath,
1146
1169
  methodExport: scenario.export,
@@ -1153,7 +1176,7 @@ var DevRunner = class {
1153
1176
  });
1154
1177
  if (!result.success) {
1155
1178
  const error = result.error?.message ?? "Scenario seed failed";
1156
- log.error("Scenario seed function failed", { id: scenario.id, error });
1179
+ log.error("runner", "Scenario seed function failed", { id: scenario.id, name: scenarioName, duration: Date.now() - startTime, error });
1157
1180
  logScenarioExecution({
1158
1181
  sessionId: this.session.sessionId,
1159
1182
  scenario,
@@ -1164,12 +1187,12 @@ var DevRunner = class {
1164
1187
  return { success: false, databases, error };
1165
1188
  }
1166
1189
  if (scenario.roles.length > 0) {
1167
- log.info("Setting role override for scenario", { roles: scenario.roles });
1190
+ log.debug("runner", "Setting role override for scenario", { roles: scenario.roles });
1168
1191
  await impersonate(this.appId, this.session.sessionId, scenario.roles);
1169
1192
  await this.refreshClientContext();
1170
1193
  }
1171
1194
  const duration = Date.now() - startTime;
1172
- log.info("Scenario complete", { id: scenario.id, duration, roles: scenario.roles });
1195
+ log.info("runner", "Scenario complete", { id: scenario.id, name: scenarioName, duration, roles: scenario.roles });
1173
1196
  logScenarioExecution({
1174
1197
  sessionId: this.session.sessionId,
1175
1198
  scenario,
@@ -1180,7 +1203,7 @@ var DevRunner = class {
1180
1203
  return { success: true, databases };
1181
1204
  } catch (err) {
1182
1205
  const error = err instanceof Error ? err.message : "Unknown error";
1183
- log.error("Scenario failed", { id: scenario.id, error });
1206
+ log.error("runner", "Scenario failed", { id: scenario.id, name: scenarioName, duration: Date.now() - startTime, error });
1184
1207
  logScenarioExecution({
1185
1208
  sessionId: this.session.sessionId,
1186
1209
  scenario,
@@ -1202,7 +1225,7 @@ var DevRunner = class {
1202
1225
  );
1203
1226
  if (this.hadConnectionWarning) {
1204
1227
  this.hadConnectionWarning = false;
1205
- log.info("Connection to platform restored");
1228
+ log.info("runner", "Connection to platform restored");
1206
1229
  devRequestEvents.emitConnectionRestored();
1207
1230
  }
1208
1231
  if (request) {
@@ -1211,31 +1234,29 @@ var DevRunner = class {
1211
1234
  this.backoffMs = 1e3;
1212
1235
  } catch (error) {
1213
1236
  if (error instanceof DevPollError && error.statusCode === 404) {
1214
- log.error("Dev session expired", { statusCode: 404 });
1237
+ log.error("runner", "Dev session expired", { statusCode: 404 });
1215
1238
  devRequestEvents.emitSessionExpired();
1216
1239
  this.isRunning = false;
1217
1240
  return;
1218
1241
  }
1219
1242
  if ((error instanceof DevPollError || error instanceof ApiError) && error.statusCode === 401) {
1220
- log.warn("Session token expired, re-authenticating");
1221
1243
  const refreshed = await this.refreshAuth();
1222
1244
  if (refreshed) {
1223
1245
  this.backoffMs = 1e3;
1224
1246
  continue;
1225
1247
  }
1226
- log.error("Re-authentication failed");
1248
+ log.error("runner", "Re-authentication failed");
1227
1249
  devRequestEvents.emitSessionExpired();
1228
1250
  this.isRunning = false;
1229
1251
  return;
1230
1252
  }
1231
1253
  if (!this.hadConnectionWarning) {
1232
1254
  this.hadConnectionWarning = true;
1233
- log.warn("Lost connection to platform, retrying");
1255
+ log.warn("runner", "Lost connection to platform, retrying");
1234
1256
  devRequestEvents.emitConnectionWarning(
1235
1257
  "Lost connection to platform, retrying..."
1236
1258
  );
1237
1259
  }
1238
- log.debug("Backing off", { ms: this.backoffMs });
1239
1260
  await this.sleep(this.backoffMs);
1240
1261
  this.backoffMs = Math.min(this.backoffMs * 2, 3e4);
1241
1262
  }
@@ -1249,9 +1270,8 @@ var DevRunner = class {
1249
1270
  method: request.methodExport,
1250
1271
  timestamp: startTime
1251
1272
  });
1252
- log.info("Method received", { requestId: request.requestId, method: request.methodExport });
1273
+ log.info("runner", "Method received", { requestId: request.requestId, method: request.methodExport, source: "poll", sessionId: this.session.sessionId });
1253
1274
  try {
1254
- log.debug("Transpiling method", { path: request.methodPath });
1255
1275
  const transpiledPath = await this.transpiler.transpile(request.methodPath);
1256
1276
  const auth = request.roleOverride ? {
1257
1277
  userId: this.session.auth.userId,
@@ -1287,13 +1307,14 @@ var DevRunner = class {
1287
1307
  );
1288
1308
  const duration = Date.now() - startTime;
1289
1309
  if (result.success) {
1290
- log.info("Method complete", { requestId: request.requestId, method: request.methodExport, duration });
1310
+ log.info("runner", "Method complete", { requestId: request.requestId, method: request.methodExport, duration, sessionId: this.session.sessionId });
1291
1311
  } else {
1292
- log.warn("Method failed", {
1312
+ log.warn("runner", "Method failed", {
1293
1313
  requestId: request.requestId,
1294
1314
  method: request.methodExport,
1295
1315
  duration,
1296
- error: result.error ? formatErrorForDisplay(result.error) : void 0
1316
+ error: result.error ? formatErrorForDisplay(result.error) : void 0,
1317
+ sessionId: this.session.sessionId
1297
1318
  });
1298
1319
  }
1299
1320
  logMethodExecution({
@@ -1317,7 +1338,7 @@ var DevRunner = class {
1317
1338
  } catch (error) {
1318
1339
  const message = error instanceof Error ? error.message : "Unknown error";
1319
1340
  const duration = Date.now() - startTime;
1320
- log.error("Method error", { requestId: request.requestId, method: request.methodExport, duration, error: message });
1341
+ log.error("runner", "Method execution error", { requestId: request.requestId, method: request.methodExport, duration, error: message, sessionId: this.session.sessionId });
1321
1342
  try {
1322
1343
  await submitDevResult(
1323
1344
  this.appId,
@@ -1330,7 +1351,7 @@ var DevRunner = class {
1330
1351
  }
1331
1352
  );
1332
1353
  } catch (submitErr) {
1333
- log.error("Failed to report method error to platform", { error: submitErr instanceof Error ? submitErr.message : String(submitErr) });
1354
+ log.error("runner", "Failed to report method error to platform", { error: submitErr instanceof Error ? submitErr.message : String(submitErr) });
1334
1355
  }
1335
1356
  logMethodExecution({
1336
1357
  requestId: request.requestId,
@@ -1361,14 +1382,14 @@ var DevRunner = class {
1361
1382
  const POLL_INTERVAL = 2e3;
1362
1383
  const MAX_ATTEMPTS = 30;
1363
1384
  try {
1364
- log.info("Session token expired, requesting re-authentication");
1385
+ log.info("runner", "Session token expired, requesting re-authentication");
1365
1386
  const { url, token } = await requestDeviceAuth();
1366
1387
  devRequestEvents.emitAuthRefreshStart(url);
1367
1388
  try {
1368
1389
  const open = (await import("open")).default;
1369
1390
  await open(url);
1370
1391
  } catch {
1371
- log.warn("Could not open browser \u2014 visit URL to re-authenticate");
1392
+ log.warn("runner", "Could not open browser \u2014 visit URL to re-authenticate");
1372
1393
  }
1373
1394
  for (let i = 0; i < MAX_ATTEMPTS; i++) {
1374
1395
  await this.sleep(POLL_INTERVAL);
@@ -1379,7 +1400,7 @@ var DevRunner = class {
1379
1400
  if (result.userId) {
1380
1401
  setUserId(result.userId);
1381
1402
  }
1382
- log.info("Re-authentication successful");
1403
+ log.info("runner", "Re-authentication successful");
1383
1404
  devRequestEvents.emitAuthRefreshSuccess();
1384
1405
  return true;
1385
1406
  }
@@ -1387,11 +1408,11 @@ var DevRunner = class {
1387
1408
  break;
1388
1409
  }
1389
1410
  }
1390
- log.error("Re-authentication timed out or was denied");
1411
+ log.error("runner", "Re-authentication timed out or was denied");
1391
1412
  devRequestEvents.emitAuthRefreshFailed();
1392
1413
  return false;
1393
1414
  } catch (err) {
1394
- log.error("Re-authentication failed", { error: err instanceof Error ? err.message : String(err) });
1415
+ log.error("runner", "Re-authentication failed", { error: err instanceof Error ? err.message : String(err) });
1395
1416
  devRequestEvents.emitAuthRefreshFailed();
1396
1417
  return false;
1397
1418
  }
@@ -1406,10 +1427,19 @@ var ndjsonLog2 = new NdjsonLog("browser.ndjson");
1406
1427
  function initBrowserLog(projectRoot) {
1407
1428
  ndjsonLog2.init(projectRoot);
1408
1429
  }
1430
+ function inferLevel(entry) {
1431
+ const type = entry.type;
1432
+ if (type === "error") return "error";
1433
+ const level = entry.level;
1434
+ if (level === "warn" || level === "error" || level === "debug") return level;
1435
+ return "info";
1436
+ }
1409
1437
  function appendBrowserLogEntries(entries) {
1410
1438
  for (const entry of entries) {
1411
1439
  ndjsonLog2.append({
1412
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
1440
+ ts: Date.now(),
1441
+ level: inferLevel(entry),
1442
+ module: "browser",
1413
1443
  ...entry
1414
1444
  });
1415
1445
  }
@@ -1439,14 +1469,14 @@ var ClientRegistry = class {
1439
1469
  alive: true,
1440
1470
  activeCommandId: null
1441
1471
  });
1442
- log.info("Browser client connected", { clientId: id, mode: hello.mode, url: hello.url });
1472
+ log.info("proxy", "Browser client connected", { clientId: id, mode: hello.mode, url: hello.url });
1443
1473
  return id;
1444
1474
  }
1445
1475
  remove(id) {
1446
1476
  const client = this.clients.get(id);
1447
1477
  if (client) {
1448
1478
  this.clients.delete(id);
1449
- log.info("Browser client disconnected", { clientId: id, mode: client.mode });
1479
+ log.info("proxy", "Browser client disconnected", { clientId: id, mode: client.mode });
1450
1480
  }
1451
1481
  return client;
1452
1482
  }
@@ -1502,7 +1532,7 @@ var ClientRegistry = class {
1502
1532
  const removed = [];
1503
1533
  for (const client of this.clients.values()) {
1504
1534
  if (!client.alive) {
1505
- log.warn("Browser client timed out (no pong)", { clientId: client.id, activeCommandId: client.activeCommandId });
1535
+ log.warn("proxy", "Browser client timed out (no pong)", { clientId: client.id, activeCommandId: client.activeCommandId });
1506
1536
  removed.push({ clientId: client.id, activeCommandId: client.activeCommandId });
1507
1537
  this.clients.delete(client.id);
1508
1538
  client.ws.terminate();
@@ -1537,7 +1567,6 @@ var DevProxy = class _DevProxy {
1537
1567
  static HELLO_TIMEOUT = 5e3;
1538
1568
  updateClientContext(context) {
1539
1569
  this.clientContext = context;
1540
- log.info("Dev proxy context updated after role change");
1541
1570
  }
1542
1571
  /**
1543
1572
  * Whether any browser agent is actively connected via WebSocket.
@@ -1552,13 +1581,26 @@ var DevProxy = class _DevProxy {
1552
1581
  dispatchBrowserCommand(steps, timeoutMs = 12e4) {
1553
1582
  if (!this.clients.hasConnected()) {
1554
1583
  return Promise.reject(
1555
- new Error("No browser connected, please refresh the MindStudio preview")
1584
+ new Error(
1585
+ "No browser connected, please refresh the MindStudio preview"
1586
+ )
1556
1587
  );
1557
1588
  }
1558
1589
  const id = randomBytes4(4).toString("hex");
1559
1590
  return new Promise((resolve2, reject) => {
1560
- this.commandQueue.push({ id, steps, timeoutMs, resolve: resolve2, reject, queuedAt: Date.now() });
1561
- log.info("Browser command queued", { id, queueLength: this.commandQueue.length, commands: steps.map((s) => s.command) });
1591
+ this.commandQueue.push({
1592
+ id,
1593
+ steps,
1594
+ timeoutMs,
1595
+ resolve: resolve2,
1596
+ reject,
1597
+ queuedAt: Date.now()
1598
+ });
1599
+ log.debug("proxy", "Browser command queued", {
1600
+ id,
1601
+ queueLength: this.commandQueue.length,
1602
+ commands: steps.map((s) => s.command)
1603
+ });
1562
1604
  this.drainCommandQueue();
1563
1605
  });
1564
1606
  }
@@ -1571,12 +1613,22 @@ var DevProxy = class _DevProxy {
1571
1613
  if (!target) break;
1572
1614
  const queued = this.commandQueue.shift();
1573
1615
  const { id, steps, timeoutMs, resolve: resolve2, reject } = queued;
1574
- log.info("Browser command sent", { id, clientId: target.id, mode: target.mode, stepCount: steps.length, commands: steps.map((s) => s.command) });
1616
+ log.info("proxy", "Browser command sent", {
1617
+ id,
1618
+ clientId: target.id,
1619
+ mode: target.mode,
1620
+ stepCount: steps.length,
1621
+ commands: steps.map((s) => s.command),
1622
+ queueWaitMs: Date.now() - queued.queuedAt
1623
+ });
1575
1624
  const timeout = setTimeout(() => {
1576
1625
  this.pendingResults.delete(id);
1577
1626
  const client = this.clients.findByCommandId(id);
1578
1627
  if (client) client.activeCommandId = null;
1579
- log.warn("Browser command timed out", { id, pendingCount: this.pendingResults.size });
1628
+ log.warn("proxy", "Browser command timed out", {
1629
+ id,
1630
+ pendingCount: this.pendingResults.size
1631
+ });
1580
1632
  reject(new Error("Browser command timed out"));
1581
1633
  this.drainCommandQueue();
1582
1634
  }, timeoutMs);
@@ -1588,6 +1640,10 @@ var DevProxy = class _DevProxy {
1588
1640
  this.pendingResults.delete(id);
1589
1641
  clearTimeout(timeout);
1590
1642
  target.activeCommandId = null;
1643
+ log.warn("proxy", "Browser command send failed", {
1644
+ id,
1645
+ clientId: target.id
1646
+ });
1591
1647
  reject(new Error("Failed to send command to browser"));
1592
1648
  }
1593
1649
  }
@@ -1598,7 +1654,10 @@ var DevProxy = class _DevProxy {
1598
1654
  broadcastToClients(action, payload) {
1599
1655
  const msg = JSON.stringify({ type: "broadcast", action, payload });
1600
1656
  const clients = this.clients.getAll();
1601
- log.info("Broadcasting to browser clients", { action, clientCount: clients.length });
1657
+ log.info("proxy", "Broadcasting to browser clients", {
1658
+ action,
1659
+ clientCount: clients.length
1660
+ });
1602
1661
  for (const client of clients) {
1603
1662
  try {
1604
1663
  client.ws.send(msg);
@@ -1629,10 +1688,13 @@ var DevProxy = class _DevProxy {
1629
1688
  this.proxyPort = assignedPort;
1630
1689
  this.startHealthCheck();
1631
1690
  this.startPingTimer();
1632
- log.info("Dev proxy started", { port: assignedPort, bind: this.bindAddress });
1691
+ log.info("proxy", "Dev proxy started", {
1692
+ port: assignedPort,
1693
+ bind: this.bindAddress
1694
+ });
1633
1695
  return assignedPort;
1634
1696
  } catch {
1635
- log.warn("Proxy port in use, trying next", { port });
1697
+ log.warn("proxy", "Proxy port in use, trying next", { port });
1636
1698
  }
1637
1699
  }
1638
1700
  throw new Error("Failed to start proxy server");
@@ -1670,7 +1732,7 @@ var DevProxy = class _DevProxy {
1670
1732
  this.wss = null;
1671
1733
  }
1672
1734
  if (this.server) {
1673
- log.info("Dev proxy stopping");
1735
+ log.info("proxy", "Dev proxy stopping");
1674
1736
  this.server.close();
1675
1737
  this.server = null;
1676
1738
  this.proxyPort = null;
@@ -1695,7 +1757,10 @@ var DevProxy = class _DevProxy {
1695
1757
  let clientId = null;
1696
1758
  const helloTimeout = setTimeout(() => {
1697
1759
  if (!clientId) {
1698
- log.warn("Browser WS client did not send hello in time, closing");
1760
+ log.warn(
1761
+ "proxy",
1762
+ "Browser WS client did not send hello in time, closing"
1763
+ );
1699
1764
  ws.close(4e3, "Hello timeout");
1700
1765
  }
1701
1766
  }, _DevProxy.HELLO_TIMEOUT);
@@ -1713,7 +1778,10 @@ var DevProxy = class _DevProxy {
1713
1778
  }
1714
1779
  clearTimeout(helloTimeout);
1715
1780
  const mode = msg.mode === "iframe" ? "iframe" : "standalone";
1716
- const viewport = msg.viewport || { w: 0, h: 0 };
1781
+ const viewport = msg.viewport || {
1782
+ w: 0,
1783
+ h: 0
1784
+ };
1717
1785
  clientId = this.clients.add(ws, {
1718
1786
  mode,
1719
1787
  url: String(msg.url || ""),
@@ -1741,7 +1809,10 @@ var DevProxy = class _DevProxy {
1741
1809
  if (clientId) {
1742
1810
  const client = this.clients.remove(clientId);
1743
1811
  if (client?.activeCommandId) {
1744
- this.rejectPendingCommand(client.activeCommandId, "Browser disconnected during command execution");
1812
+ this.rejectPendingCommand(
1813
+ client.activeCommandId,
1814
+ "Browser disconnected during command execution"
1815
+ );
1745
1816
  }
1746
1817
  }
1747
1818
  });
@@ -1751,12 +1822,16 @@ var DevProxy = class _DevProxy {
1751
1822
  handleCommandResult(msg) {
1752
1823
  const id = msg.id;
1753
1824
  if (!id) {
1754
- log.warn("Browser command result received with no id");
1825
+ log.warn("proxy", "Browser command result received with no id");
1755
1826
  return;
1756
1827
  }
1757
1828
  const pending2 = this.pendingResults.get(id);
1758
1829
  if (pending2) {
1759
- log.info("Browser command result received", { id, stepCount: msg.steps?.length, duration: msg.duration });
1830
+ log.info("proxy", "Browser command result received", {
1831
+ id,
1832
+ stepCount: msg.steps?.length,
1833
+ duration: msg.duration
1834
+ });
1760
1835
  clearTimeout(pending2.timeout);
1761
1836
  this.pendingResults.delete(id);
1762
1837
  const client = this.clients.findByCommandId(id);
@@ -1764,7 +1839,11 @@ var DevProxy = class _DevProxy {
1764
1839
  pending2.resolve(msg);
1765
1840
  this.drainCommandQueue();
1766
1841
  } else {
1767
- log.warn("Browser command result received but no pending command found", { id, pendingIds: [...this.pendingResults.keys()] });
1842
+ log.warn(
1843
+ "proxy",
1844
+ "Browser command result received but no pending command found",
1845
+ { id, pendingIds: [...this.pendingResults.keys()] }
1846
+ );
1768
1847
  }
1769
1848
  }
1770
1849
  rejectPendingCommand(commandId, reason) {
@@ -1773,7 +1852,7 @@ var DevProxy = class _DevProxy {
1773
1852
  clearTimeout(pending2.timeout);
1774
1853
  this.pendingResults.delete(commandId);
1775
1854
  pending2.resolve({ id: commandId, steps: [], error: reason });
1776
- log.warn("Pending command rejected", { id: commandId, reason });
1855
+ log.warn("proxy", "Pending command rejected", { id: commandId, reason });
1777
1856
  this.drainCommandQueue();
1778
1857
  }
1779
1858
  }
@@ -1785,7 +1864,10 @@ var DevProxy = class _DevProxy {
1785
1864
  const removed = this.clients.sweepDead();
1786
1865
  for (const { activeCommandId } of removed) {
1787
1866
  if (activeCommandId) {
1788
- this.rejectPendingCommand(activeCommandId, "Browser client timed out");
1867
+ this.rejectPendingCommand(
1868
+ activeCommandId,
1869
+ "Browser client timed out"
1870
+ );
1789
1871
  }
1790
1872
  }
1791
1873
  this.clients.pingAll();
@@ -1809,7 +1891,7 @@ var DevProxy = class _DevProxy {
1809
1891
  markUpstreamDown() {
1810
1892
  if (!this.upstreamUp) return;
1811
1893
  this.upstreamUp = false;
1812
- log.info("Upstream dev server marked as down (explicit signal)");
1894
+ log.info("proxy", "Upstream dev server marked as down (explicit signal)");
1813
1895
  this.scheduleHealthCheck(_DevProxy.HEALTH_CHECK_INTERVAL_DOWN);
1814
1896
  }
1815
1897
  startHealthCheck() {
@@ -1836,9 +1918,9 @@ var DevProxy = class _DevProxy {
1836
1918
  this.upstreamUp = false;
1837
1919
  }
1838
1920
  if (wasUp && !this.upstreamUp) {
1839
- log.warn("Upstream dev server is down");
1921
+ log.warn("proxy", "Upstream dev server is down");
1840
1922
  } else if (!wasUp && this.upstreamUp) {
1841
- log.info("Upstream dev server is back up, reloading browser");
1923
+ log.info("proxy", "Upstream dev server is back up, reloading browser");
1842
1924
  this.broadcastToClients("reload");
1843
1925
  }
1844
1926
  const interval = this.upstreamUp ? _DevProxy.HEALTH_CHECK_INTERVAL : _DevProxy.HEALTH_CHECK_INTERVAL_DOWN;
@@ -1891,7 +1973,10 @@ var DevProxy = class _DevProxy {
1891
1973
  port: this.upstreamPort,
1892
1974
  path: clientReq.url,
1893
1975
  method: clientReq.method,
1894
- headers: { ...clientReq.headers, host: `localhost:${this.upstreamPort}` }
1976
+ headers: {
1977
+ ...clientReq.headers,
1978
+ host: `localhost:${this.upstreamPort}`
1979
+ }
1895
1980
  },
1896
1981
  (upstreamRes) => {
1897
1982
  const contentType = upstreamRes.headers["content-type"] ?? "";
@@ -1910,7 +1995,6 @@ var DevProxy = class _DevProxy {
1910
1995
  };
1911
1996
  delete headers["content-encoding"];
1912
1997
  delete headers["etag"];
1913
- log.debug("Dev proxy injected context into HTML", { path: clientReq.url, size: html.length });
1914
1998
  clientRes.writeHead(upstreamRes.statusCode ?? 200, headers);
1915
1999
  clientRes.end(html);
1916
2000
  });
@@ -1927,7 +2011,10 @@ var DevProxy = class _DevProxy {
1927
2011
  }
1928
2012
  );
1929
2013
  upstreamReq.on("error", (err) => {
1930
- log.warn("Dev proxy cannot reach dev server", { path: clientReq.url, error: err.message });
2014
+ log.warn("proxy", "Dev proxy cannot reach dev server", {
2015
+ path: clientReq.url,
2016
+ error: err.message
2017
+ });
1931
2018
  clientRes.writeHead(502);
1932
2019
  clientRes.end(`Proxy error: ${err.message}`);
1933
2020
  });
@@ -1994,7 +2081,9 @@ var DevProxy = class _DevProxy {
1994
2081
  clientRes.end(body);
1995
2082
  } catch (err) {
1996
2083
  clientRes.writeHead(502, cors);
1997
- clientRes.end(`Font proxy error: ${err instanceof Error ? err.message : String(err)}`);
2084
+ clientRes.end(
2085
+ `Font proxy error: ${err instanceof Error ? err.message : String(err)}`
2086
+ );
1998
2087
  }
1999
2088
  }
2000
2089
  /**
@@ -2016,7 +2105,6 @@ ${agentScript}`;
2016
2105
  // Upstream WebSocket forwarding (HMR etc.)
2017
2106
  // ---------------------------------------------------------------------------
2018
2107
  handleUpstreamUpgrade(clientReq, clientSocket, head) {
2019
- log.debug("Dev proxy WebSocket upgrade (upstream)", { path: clientReq.url });
2020
2108
  const options = {
2021
2109
  hostname: "127.0.0.1",
2022
2110
  port: this.upstreamPort,
@@ -2056,13 +2144,10 @@ ${agentScript}`;
2056
2144
 
2057
2145
  // src/dev/config/app-config.ts
2058
2146
  import { readFileSync, existsSync as existsSync2 } from "fs";
2059
- import { join as join4, dirname as dirname2 } from "path";
2147
+ import { join as join5, dirname as dirname2 } from "path";
2060
2148
  function detectAppConfig(cwd = process.cwd()) {
2061
- const appJsonPath = join4(cwd, "mindstudio.json");
2062
- if (!existsSync2(appJsonPath)) {
2063
- log.debug("mindstudio.json not found", { path: appJsonPath });
2064
- return null;
2065
- }
2149
+ const appJsonPath = join5(cwd, "mindstudio.json");
2150
+ if (!existsSync2(appJsonPath)) return null;
2066
2151
  try {
2067
2152
  const raw = readFileSync(appJsonPath, "utf-8");
2068
2153
  const parsed = JSON.parse(raw);
@@ -2079,7 +2164,7 @@ function detectAppConfig(cwd = process.cwd()) {
2079
2164
  scenarios: parsed.scenarios ?? [],
2080
2165
  interfaces: parsed.interfaces ?? []
2081
2166
  };
2082
- log.info("Loaded mindstudio.json", {
2167
+ log.info("config", "Loaded mindstudio.json", {
2083
2168
  appId: config2.appId,
2084
2169
  roles: config2.roles.length,
2085
2170
  methods: config2.methods.length,
@@ -2089,7 +2174,7 @@ function detectAppConfig(cwd = process.cwd()) {
2089
2174
  });
2090
2175
  return config2;
2091
2176
  } catch (err) {
2092
- log.warn("Failed to parse mindstudio.json", { error: err instanceof Error ? err.message : String(err) });
2177
+ log.warn("config", "Failed to parse mindstudio.json", { error: err instanceof Error ? err.message : String(err) });
2093
2178
  return null;
2094
2179
  }
2095
2180
  }
@@ -2100,7 +2185,7 @@ function getWebInterfaceConfig(appConfig, cwd = process.cwd()) {
2100
2185
  if (!webInterface) {
2101
2186
  return null;
2102
2187
  }
2103
- const configPath = join4(cwd, webInterface.path);
2188
+ const configPath = join5(cwd, webInterface.path);
2104
2189
  if (!existsSync2(configPath)) {
2105
2190
  return null;
2106
2191
  }
@@ -2126,14 +2211,14 @@ function getWebProjectDir(appConfig, cwd = process.cwd()) {
2126
2211
  if (!webInterface) {
2127
2212
  return null;
2128
2213
  }
2129
- return dirname2(join4(cwd, webInterface.path));
2214
+ return dirname2(join5(cwd, webInterface.path));
2130
2215
  }
2131
2216
  function readTableSources(appConfig, cwd = process.cwd()) {
2132
2217
  const results = [];
2133
2218
  for (const table of appConfig.tables) {
2134
- const filePath = join4(cwd, table.path);
2219
+ const filePath = join5(cwd, table.path);
2135
2220
  if (!existsSync2(filePath)) {
2136
- log.warn("Table source file not found", { table: table.export, path: table.path });
2221
+ log.warn("config", "Table source file not found", { table: table.export, path: table.path });
2137
2222
  continue;
2138
2223
  }
2139
2224
  try {
@@ -2141,11 +2226,11 @@ function readTableSources(appConfig, cwd = process.cwd()) {
2141
2226
  const name = table.export;
2142
2227
  results.push({ name, source });
2143
2228
  } catch (err) {
2144
- log.warn("Table source file unreadable", { table: table.export, path: table.path, error: err instanceof Error ? err.message : String(err) });
2229
+ log.warn("config", "Table source file unreadable", { table: table.export, path: table.path, error: err instanceof Error ? err.message : String(err) });
2145
2230
  }
2146
2231
  }
2147
2232
  if (results.length < appConfig.tables.length) {
2148
- log.warn("Missing " + (appConfig.tables.length - results.length) + " table source file(s)", { found: results.length, expected: appConfig.tables.length });
2233
+ log.warn("config", "Table source files missing", { missing: appConfig.tables.length - results.length, found: results.length, expected: appConfig.tables.length });
2149
2234
  }
2150
2235
  return results;
2151
2236
  }
@@ -2155,9 +2240,9 @@ function findDirsNeedingInstall(appConfig, cwd = process.cwd()) {
2155
2240
  const firstMethodPath = appConfig.methods[0].path;
2156
2241
  const parts = firstMethodPath.split("/");
2157
2242
  for (let i = parts.length - 1; i >= 1; i--) {
2158
- const candidate = join4(cwd, ...parts.slice(0, i));
2159
- if (existsSync2(join4(candidate, "package.json"))) {
2160
- if (!existsSync2(join4(candidate, "node_modules"))) {
2243
+ const candidate = join5(cwd, ...parts.slice(0, i));
2244
+ if (existsSync2(join5(candidate, "package.json"))) {
2245
+ if (!existsSync2(join5(candidate, "node_modules"))) {
2161
2246
  dirs.push(candidate);
2162
2247
  }
2163
2248
  break;
@@ -2165,8 +2250,8 @@ function findDirsNeedingInstall(appConfig, cwd = process.cwd()) {
2165
2250
  }
2166
2251
  }
2167
2252
  const webProjectDir = getWebProjectDir(appConfig, cwd);
2168
- if (webProjectDir && existsSync2(join4(webProjectDir, "package.json"))) {
2169
- if (!existsSync2(join4(webProjectDir, "node_modules"))) {
2253
+ if (webProjectDir && existsSync2(join5(webProjectDir, "package.json"))) {
2254
+ if (!existsSync2(join5(webProjectDir, "node_modules"))) {
2170
2255
  dirs.push(webProjectDir);
2171
2256
  }
2172
2257
  }
@@ -2195,11 +2280,11 @@ function detectGitBranch() {
2195
2280
 
2196
2281
  // src/dev/config/table-watcher.ts
2197
2282
  import { watch } from "chokidar";
2198
- import { join as join5, dirname as dirname3, basename as basename2 } from "path";
2283
+ import { join as join6, dirname as dirname3, basename as basename2 } from "path";
2199
2284
  function watchTableFiles(tables, cwd, onChanged) {
2200
2285
  if (tables.length === 0) return () => {
2201
2286
  };
2202
- const filePaths = tables.map((t) => join5(cwd, t.path));
2287
+ const filePaths = tables.map((t) => join6(cwd, t.path));
2203
2288
  let syncTimer;
2204
2289
  const watcher = watch(filePaths, {
2205
2290
  ignoreInitial: true,
@@ -2212,13 +2297,13 @@ function watchTableFiles(tables, cwd, onChanged) {
2212
2297
  });
2213
2298
  const dirToFiles = /* @__PURE__ */ new Map();
2214
2299
  for (const table of tables) {
2215
- const absPath = join5(cwd, table.path);
2300
+ const absPath = join6(cwd, table.path);
2216
2301
  const dir = dirname3(absPath);
2217
2302
  const file = basename2(absPath);
2218
2303
  if (!dirToFiles.has(dir)) dirToFiles.set(dir, /* @__PURE__ */ new Set());
2219
2304
  dirToFiles.get(dir).add(file);
2220
2305
  }
2221
- log.info("Watching table source files", {
2306
+ log.info("config", "Watching table source files", {
2222
2307
  dirs: dirToFiles.size,
2223
2308
  tables: tables.length
2224
2309
  });
@@ -2230,9 +2315,9 @@ function watchTableFiles(tables, cwd, onChanged) {
2230
2315
 
2231
2316
  // src/dev/config/config-watcher.ts
2232
2317
  import { watch as watch2 } from "chokidar";
2233
- import { join as join6 } from "path";
2318
+ import { join as join7 } from "path";
2234
2319
  function watchConfigFile(cwd, onChanged) {
2235
- const configPath = join6(cwd, "mindstudio.json");
2320
+ const configPath = join7(cwd, "mindstudio.json");
2236
2321
  let debounceTimer;
2237
2322
  const watcher = watch2(configPath, {
2238
2323
  ignoreInitial: true,
@@ -2244,7 +2329,7 @@ function watchConfigFile(cwd, onChanged) {
2244
2329
  onChanged();
2245
2330
  }, 500);
2246
2331
  });
2247
- log.info("Watching mindstudio.json for changes", { path: configPath });
2332
+ log.info("config", "Watching mindstudio.json for changes", { path: configPath });
2248
2333
  return () => {
2249
2334
  clearTimeout(debounceTimer);
2250
2335
  watcher.close();
@@ -2299,4 +2384,4 @@ export {
2299
2384
  watchTableFiles,
2300
2385
  watchConfigFile
2301
2386
  };
2302
- //# sourceMappingURL=chunk-VCBGX5ND.js.map
2387
+ //# sourceMappingURL=chunk-JRLMRABX.js.map