@mindstudio-ai/local-model-tunnel 0.5.41 → 0.5.42

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.
@@ -7,7 +7,7 @@ import {
7
7
  setProviderInstallPath,
8
8
  submitProgress,
9
9
  submitResult
10
- } from "./chunk-VO5KLV5S.js";
10
+ } from "./chunk-6LWKL7BC.js";
11
11
 
12
12
  // src/providers/ollama/index.ts
13
13
  import { Ollama } from "ollama";
@@ -1395,4 +1395,4 @@ export {
1395
1395
  requestEvents,
1396
1396
  TunnelRunner
1397
1397
  };
1398
- //# sourceMappingURL=chunk-DKTUVHTX.js.map
1398
+ //# sourceMappingURL=chunk-2ND2YJQR.js.map
@@ -421,6 +421,45 @@ function logScenarioExecution(entry) {
421
421
  stats: entry.result?.stats ?? null
422
422
  });
423
423
  }
424
+ function logMethodStart(requestId, sessionId, method, input) {
425
+ ndjsonLog.append({
426
+ ts: Date.now(),
427
+ level: "info",
428
+ module: "execution",
429
+ msg: "Method started",
430
+ type: "method-start",
431
+ requestId,
432
+ sessionId,
433
+ method,
434
+ input
435
+ });
436
+ }
437
+ function logMethodStdout(requestId, sessionId, method, lines) {
438
+ ndjsonLog.append({
439
+ ts: Date.now(),
440
+ level: "info",
441
+ module: "execution",
442
+ msg: "Method stdout",
443
+ type: "method-stdout",
444
+ requestId,
445
+ sessionId,
446
+ method,
447
+ stdout: lines
448
+ });
449
+ }
450
+ function logBackgroundStdout(requestId, sessionId, method, lines) {
451
+ ndjsonLog.append({
452
+ ts: Date.now(),
453
+ level: "info",
454
+ module: "execution",
455
+ msg: "Background stdout",
456
+ type: "method-background-stdout",
457
+ requestId,
458
+ sessionId,
459
+ method,
460
+ stdout: lines
461
+ });
462
+ }
424
463
  function closeRequestLog() {
425
464
  ndjsonLog.close();
426
465
  }
@@ -582,6 +621,7 @@ function findNearestNodeModules(startDir) {
582
621
  // src/dev/execution/executor.ts
583
622
  import { fork } from "child_process";
584
623
  import { writeFile, unlink as unlink2 } from "fs/promises";
624
+ import { readFileSync } from "fs";
585
625
  import { join as join4 } from "path";
586
626
  import { tmpdir } from "os";
587
627
  import { randomBytes } from "crypto";
@@ -589,9 +629,10 @@ var EXECUTION_TIMEOUT_MS = 30 * 60 * 1e3;
589
629
  var worker = null;
590
630
  var workerScriptPath = null;
591
631
  var workerProjectRoot = null;
632
+ var workerSupportsAls = false;
592
633
  var pending = /* @__PURE__ */ new Map();
593
- function buildWorkerScript() {
594
- return `
634
+ var requestMeta = /* @__PURE__ */ new Map();
635
+ var SERIALIZE_ERROR_FN = `
595
636
  function serializeError(err) {
596
637
  if (!err) return { message: 'Unknown error' };
597
638
 
@@ -626,6 +667,117 @@ function serializeError(err) {
626
667
 
627
668
  return serialized;
628
669
  }
670
+ `;
671
+ function buildAlsWorkerScript() {
672
+ return `
673
+ import { AsyncLocalStorage } from 'node:async_hooks';
674
+ import { format } from 'node:util';
675
+ import { runWithContext } from '@mindstudio-ai/agent';
676
+
677
+ ${SERIALIZE_ERROR_FN}
678
+
679
+ // Per-request console capture via AsyncLocalStorage
680
+ const consoleAls = new AsyncLocalStorage();
681
+ const _origLog = console.log;
682
+ const _origWarn = console.warn;
683
+ const _origError = console.error;
684
+
685
+ console.log = (...args) => {
686
+ const stdout = consoleAls.getStore();
687
+ if (stdout) stdout.push(format(...args));
688
+ _origLog(...args);
689
+ };
690
+ console.warn = (...args) => {
691
+ const stdout = consoleAls.getStore();
692
+ if (stdout) stdout.push(format(...args));
693
+ _origWarn(...args);
694
+ };
695
+ console.error = (...args) => {
696
+ const stdout = consoleAls.getStore();
697
+ if (stdout) stdout.push(format(...args));
698
+ _origError(...args);
699
+ };
700
+
701
+ process.on('message', async (msg) => {
702
+ const { id, transpiledPath, methodExport, input, auth, databases, authorizationToken, apiBaseUrl, streamId } = msg;
703
+
704
+ const ctx = {
705
+ callbackToken: authorizationToken,
706
+ remoteHostname: apiBaseUrl,
707
+ auth: auth ?? { userId: null, roleAssignments: [] },
708
+ databases: databases ?? [],
709
+ streamId: streamId ?? undefined,
710
+ };
711
+
712
+ const stdout = [];
713
+ let flushed = 0;
714
+ let done = false;
715
+
716
+ // Flush new stdout lines every 1s while the method is running.
717
+ // After the method returns, switches to background-stdout type.
718
+ const flushInterval = setInterval(() => {
719
+ if (stdout.length > flushed) {
720
+ const lines = stdout.slice(flushed);
721
+ flushed = stdout.length;
722
+ try {
723
+ process.send({ type: done ? 'background-stdout' : 'stdout', id, lines });
724
+ } catch {}
725
+ idleTicks = 0;
726
+ } else if (done) {
727
+ idleTicks++;
728
+ if (idleTicks >= 2) {
729
+ clearInterval(flushInterval);
730
+ try { process.send({ type: 'stdout-end', id }); } catch {}
731
+ }
732
+ }
733
+ }, 1000);
734
+ let idleTicks = 0;
735
+
736
+ process.send({ type: 'start', id });
737
+
738
+ const startTime = Date.now();
739
+
740
+ try {
741
+ const returnValue = await consoleAls.run(stdout, () =>
742
+ runWithContext(ctx, async () => {
743
+ const mod = await import(transpiledPath + '?t=' + Date.now());
744
+ const fn = mod[methodExport];
745
+ if (typeof fn !== 'function') {
746
+ throw new Error(methodExport + ' is not a function (got ' + typeof fn + ')');
747
+ }
748
+ return fn(input);
749
+ }),
750
+ );
751
+ const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };
752
+
753
+ // Final flush of any remaining lines before sending result
754
+ if (stdout.length > flushed) {
755
+ try { process.send({ type: 'stdout', id, lines: stdout.slice(flushed) }); } catch {}
756
+ flushed = stdout.length;
757
+ }
758
+
759
+ done = true;
760
+ process.send({ id, success: true, output: returnValue, stats });
761
+ } catch (err) {
762
+ const stats = { memoryUsedBytes: process.memoryUsage().heapUsed, executionTimeMs: Date.now() - startTime };
763
+
764
+ if (stdout.length > flushed) {
765
+ try { process.send({ type: 'stdout', id, lines: stdout.slice(flushed) }); } catch {}
766
+ flushed = stdout.length;
767
+ }
768
+
769
+ done = true;
770
+ process.send({ id, success: false, error: serializeError(err), stats });
771
+ }
772
+ });
773
+
774
+ // Signal ready
775
+ process.send({ type: 'ready' });
776
+ `;
777
+ }
778
+ function buildLegacyWorkerScript() {
779
+ return `
780
+ ${SERIALIZE_ERROR_FN}
629
781
 
630
782
  // Save original console methods so we can restore after each request
631
783
  const _origLog = console.log;
@@ -677,6 +829,17 @@ process.on('message', async (msg) => {
677
829
  process.send({ type: 'ready' });
678
830
  `;
679
831
  }
832
+ function detectAlsSupport(projectRoot) {
833
+ try {
834
+ const pkgPath = join4(projectRoot, "node_modules", "@mindstudio-ai", "agent", "package.json");
835
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
836
+ const parts = (pkg.version || "").split(".").map(Number);
837
+ const [major = 0, minor = 0, patch = 0] = parts;
838
+ return major > 0 || minor > 1 || minor === 1 && patch >= 46;
839
+ } catch {
840
+ return false;
841
+ }
842
+ }
680
843
  async function ensureWorker(projectRoot) {
681
844
  if (worker?.connected && workerProjectRoot === projectRoot) {
682
845
  return worker;
@@ -695,14 +858,17 @@ async function ensureWorker(projectRoot) {
695
858
  });
696
859
  workerScriptPath = null;
697
860
  }
861
+ workerSupportsAls = detectAlsSupport(projectRoot);
862
+ log.info("executor", "SDK context support", { als: workerSupportsAls });
698
863
  const scriptPath = join4(
699
864
  tmpdir(),
700
865
  `ms-dev-worker-${randomBytes(4).toString("hex")}.mjs`
701
866
  );
702
- await writeFile(scriptPath, buildWorkerScript(), "utf-8");
867
+ const script = workerSupportsAls ? buildAlsWorkerScript() : buildLegacyWorkerScript();
868
+ await writeFile(scriptPath, script, "utf-8");
703
869
  workerScriptPath = scriptPath;
704
870
  workerProjectRoot = projectRoot;
705
- log.debug("executor", "Spawning method execution process", { cwd: projectRoot, scriptPath });
871
+ log.debug("executor", "Spawning method execution process", { cwd: projectRoot, scriptPath, als: workerSupportsAls });
706
872
  const child = fork(scriptPath, [], {
707
873
  cwd: projectRoot,
708
874
  stdio: ["ignore", "pipe", "pipe", "ipc"],
@@ -721,6 +887,21 @@ async function ensureWorker(projectRoot) {
721
887
  });
722
888
  child.on("message", (msg) => {
723
889
  if (!msg?.id) return;
890
+ const meta = requestMeta.get(msg.id);
891
+ switch (msg.type) {
892
+ case "start":
893
+ if (meta) logMethodStart(msg.id, meta.sessionId, meta.method, meta.input);
894
+ return;
895
+ case "stdout":
896
+ if (meta && msg.lines?.length) logMethodStdout(msg.id, meta.sessionId, meta.method, msg.lines);
897
+ return;
898
+ case "background-stdout":
899
+ if (meta && msg.lines?.length) logBackgroundStdout(msg.id, meta.sessionId, meta.method, msg.lines);
900
+ return;
901
+ case "stdout-end":
902
+ requestMeta.delete(msg.id);
903
+ return;
904
+ }
724
905
  const req = pending.get(msg.id);
725
906
  if (!req) return;
726
907
  pending.delete(msg.id);
@@ -752,6 +933,9 @@ function enqueue(fn) {
752
933
  return task;
753
934
  }
754
935
  function executeMethod(opts) {
936
+ if (workerSupportsAls) {
937
+ return executeMethodInWorker(opts);
938
+ }
755
939
  return enqueue(() => executeMethodInWorker(opts));
756
940
  }
757
941
  async function executeMethodInWorker(opts) {
@@ -768,6 +952,9 @@ async function executeMethodInWorker(opts) {
768
952
  });
769
953
  }, EXECUTION_TIMEOUT_MS);
770
954
  pending.set(id, { resolve: resolve2, timer });
955
+ if (opts.sessionId) {
956
+ requestMeta.set(id, { sessionId: opts.sessionId, method: opts.methodExport, input: opts.input });
957
+ }
771
958
  w.send({
772
959
  id,
773
960
  transpiledPath: opts.transpiledPath,
@@ -793,10 +980,12 @@ async function cleanupWorker() {
793
980
  workerScriptPath = null;
794
981
  }
795
982
  workerProjectRoot = null;
983
+ workerSupportsAls = false;
796
984
  for (const [, req] of pending) {
797
985
  clearTimeout(req.timer);
798
986
  }
799
987
  pending.clear();
988
+ requestMeta.clear();
800
989
  queueTail = Promise.resolve();
801
990
  }
802
991
 
@@ -988,7 +1177,7 @@ function formatErrorForDisplay(error) {
988
1177
  }
989
1178
 
990
1179
  // src/dev/execution/agent-config.ts
991
- import { readFileSync } from "fs";
1180
+ import { readFileSync as readFileSync2 } from "fs";
992
1181
  import { join as join5, dirname as dirname2 } from "path";
993
1182
  function readAgentConfig(projectRoot, appConfig) {
994
1183
  const agentInterface = appConfig.interfaces.find(
@@ -1000,7 +1189,7 @@ function readAgentConfig(projectRoot, appConfig) {
1000
1189
  const configPath = join5(projectRoot, agentInterface.path);
1001
1190
  let raw;
1002
1191
  try {
1003
- raw = readFileSync(configPath, "utf-8");
1192
+ raw = readFileSync2(configPath, "utf-8");
1004
1193
  } catch {
1005
1194
  throw new Error(
1006
1195
  `Agent config not found at ${agentInterface.path} \u2014 run your build command`
@@ -1012,7 +1201,7 @@ function readAgentConfig(projectRoot, appConfig) {
1012
1201
  const systemPromptPath = join5(agentDir, config2.systemPrompt);
1013
1202
  let systemPrompt;
1014
1203
  try {
1015
- systemPrompt = readFileSync(systemPromptPath, "utf-8");
1204
+ systemPrompt = readFileSync2(systemPromptPath, "utf-8");
1016
1205
  } catch {
1017
1206
  throw new Error(
1018
1207
  `Agent system prompt not found at ${config2.systemPrompt} \u2014 run your build command`
@@ -1023,7 +1212,7 @@ function readAgentConfig(projectRoot, appConfig) {
1023
1212
  const descPath = join5(agentDir, tool.description);
1024
1213
  let description;
1025
1214
  try {
1026
- description = readFileSync(descPath, "utf-8");
1215
+ description = readFileSync2(descPath, "utf-8");
1027
1216
  } catch {
1028
1217
  throw new Error(
1029
1218
  `Agent tool description not found at ${tool.description} for method "${tool.method}" \u2014 run your build command`
@@ -1168,7 +1357,8 @@ var DevRunner = class {
1168
1357
  databases: this.session.databases,
1169
1358
  authorizationToken,
1170
1359
  apiBaseUrl: getApiBaseUrl(),
1171
- projectRoot: this.projectRoot
1360
+ projectRoot: this.projectRoot,
1361
+ sessionId: this.session.sessionId
1172
1362
  });
1173
1363
  const duration = Date.now() - startTime;
1174
1364
  if (result.success) {
@@ -1246,7 +1436,8 @@ var DevRunner = class {
1246
1436
  databases: this.session.databases,
1247
1437
  authorizationToken,
1248
1438
  apiBaseUrl: getApiBaseUrl(),
1249
- projectRoot: this.projectRoot
1439
+ projectRoot: this.projectRoot,
1440
+ sessionId: this.session.sessionId
1250
1441
  });
1251
1442
  if (!result.success) {
1252
1443
  const error = result.error?.message ?? "Scenario seed failed";
@@ -1387,6 +1578,7 @@ var DevRunner = class {
1387
1578
  authorizationToken: request.authorizationToken,
1388
1579
  apiBaseUrl: getApiBaseUrl(),
1389
1580
  projectRoot: this.projectRoot,
1581
+ sessionId: this.session.sessionId,
1390
1582
  streamId: request.streamId
1391
1583
  });
1392
1584
  const t2 = Date.now();
@@ -2669,13 +2861,13 @@ ${agentScript}`;
2669
2861
  };
2670
2862
 
2671
2863
  // src/dev/config/app-config.ts
2672
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
2864
+ import { readFileSync as readFileSync3, existsSync as existsSync2 } from "fs";
2673
2865
  import { join as join6, dirname as dirname3 } from "path";
2674
2866
  function detectAppConfig(cwd = process.cwd()) {
2675
2867
  const appJsonPath = join6(cwd, "mindstudio.json");
2676
2868
  if (!existsSync2(appJsonPath)) return null;
2677
2869
  try {
2678
- const raw = readFileSync2(appJsonPath, "utf-8");
2870
+ const raw = readFileSync3(appJsonPath, "utf-8");
2679
2871
  const parsed = JSON.parse(raw);
2680
2872
  if (!parsed.name || !Array.isArray(parsed.methods)) {
2681
2873
  return null;
@@ -2717,7 +2909,7 @@ function getWebInterfaceConfig(appConfig, cwd = process.cwd()) {
2717
2909
  return null;
2718
2910
  }
2719
2911
  try {
2720
- const raw = readFileSync2(configPath, "utf-8");
2912
+ const raw = readFileSync3(configPath, "utf-8");
2721
2913
  const parsed = JSON.parse(raw);
2722
2914
  const web = parsed.web;
2723
2915
  if (!web || typeof web !== "object") {
@@ -2749,7 +2941,7 @@ function readTableSources(appConfig, cwd = process.cwd()) {
2749
2941
  continue;
2750
2942
  }
2751
2943
  try {
2752
- const source = readFileSync2(filePath, "utf-8");
2944
+ const source = readFileSync3(filePath, "utf-8");
2753
2945
  const name = table.export;
2754
2946
  results.push({ name, source });
2755
2947
  } catch (err) {
@@ -2887,6 +3079,8 @@ export {
2887
3079
  getUploadUrl,
2888
3080
  createAuthSession,
2889
3081
  devRequestEvents,
3082
+ initRequestLog,
3083
+ closeRequestLog,
2890
3084
  pollForRequest,
2891
3085
  submitProgress,
2892
3086
  submitResult,
@@ -2897,8 +3091,6 @@ export {
2897
3091
  pollDeviceAuth,
2898
3092
  getEditorSessions,
2899
3093
  disconnectHeartbeat,
2900
- initRequestLog,
2901
- closeRequestLog,
2902
3094
  DevRunner,
2903
3095
  initBrowserLog,
2904
3096
  closeBrowserLog,
@@ -2913,4 +3105,4 @@ export {
2913
3105
  watchTableFiles,
2914
3106
  watchConfigFile
2915
3107
  };
2916
- //# sourceMappingURL=chunk-VO5KLV5S.js.map
3108
+ //# sourceMappingURL=chunk-6LWKL7BC.js.map