loom-agent 1.2.6 → 1.2.8

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/bin/loom-tui.js CHANGED
@@ -36,7 +36,10 @@ process.env.LOOM_BIN_NAME = "loom";
36
36
  const bun = findBun();
37
37
 
38
38
  if (bun) {
39
- const result = spawnSync(bun, ['run', entry, ...process.argv.slice(2)], {
39
+ // Pin Solid to its CLIENT build: from this spawn context bun can resolve
40
+ // solid-js under the "node" export condition (= SSR build, renders one
41
+ // static frame then ignores all signal updates -> frozen splash).
42
+ const result = spawnSync(bun, ['--conditions=browser', 'run', entry, ...process.argv.slice(2)], {
40
43
  stdio: 'inherit',
41
44
  cwd: pkgRoot,
42
45
  env: process.env,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "loom-agent",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "git+https://github.com/toshalkumbhar8979-design/loomcode.git"
package/src/core/cli.js CHANGED
@@ -566,7 +566,10 @@ if (args.includes('--help') || args.includes('-h')) {
566
566
  const pkgRoot = path.join(__dirname, '..', '..');
567
567
  process.env.LOOM_START_CWD = process.cwd();
568
568
  process.env.LOOM_BIN_NAME = "loom";
569
- const tuiArgs = [tuiEntry];
569
+ // --conditions=browser pins Solid to its client build (see
570
+ // bin/loom-tui.js) — without it the SSR build loads and the TUI
571
+ // renders one static frame then never updates.
572
+ const tuiArgs = ['--conditions=browser', tuiEntry];
570
573
  if (sessionId) tuiArgs.push('-s', sessionId);
571
574
  if (autoMode) tuiArgs.push('--auto');
572
575
  const prompt = promptArgs.join(' ');
package/src/tui/App.tsx CHANGED
@@ -1506,7 +1506,7 @@ export function App(props: { initialPrompt?: string; resumeSession?: string; aut
1506
1506
  _skillDoneOff = on("turn:end", function(d: any) {
1507
1507
  if (d?.skills?.length) showToast("skill handled: " + d.skills.join(", "), "ok");
1508
1508
  });
1509
- (globalThis as any).__loomTrace?.("onMount-done");
1509
+ (globalThis as any).__loomTrace("onMount-done", new Error("mount complete"));
1510
1510
  });
1511
1511
  onCleanup(function() { persistUi(); if (_skillToastOff) _skillToastOff(); if (_skillDoneOff) _skillDoneOff(); });
1512
1512
 
@@ -45,6 +45,22 @@ function record(kind, err) {
45
45
  }
46
46
  process.on("uncaughtException", (e) => { record("uncaughtException", e); });
47
47
  process.on("unhandledRejection", (r) => { record("unhandledRejection", r); });
48
+ globalThis.__loomTrace = record;
49
+
50
+ // Watchdog: append a heartbeat every 3s carrying measured event-loop lag.
51
+ // A synchronous hang shows up as a timestamp gap exactly covering the
52
+ // blocking phase; markers around it name the guilty step.
53
+ const __hbStart = Date.now();
54
+ let __hbTick = 0;
55
+ let __hbScheduled = __hbStart;
56
+ const __hbTimer = setInterval(() => {
57
+ const now = Date.now();
58
+ const lag = now - __hbScheduled;
59
+ record("heartbeat", new Error(`tick=${++__hbTick} lag=${lag}ms uptime=${now - __hbStart}ms`));
60
+ __hbScheduled = now + 3000;
61
+ }, 3000);
62
+ try { __hbTimer.unref?.(); } catch {}
63
+ process.on("exit", () => { try { record("exit", new Error(`uptime=${Date.now() - __hbStart}ms ticks=${__hbTick}`)); } catch {} });
48
64
 
49
65
  record("boot", new Error(
50
66
  `argv=${JSON.stringify(process.argv.slice(1))} cwd=${process.cwd()} ` +
package/src/tui-open.tsx CHANGED
@@ -5,6 +5,7 @@ import { render } from "@opentui/solid";
5
5
  import { App } from "./tui/App.tsx";
6
6
  import { defaultMcpInstall } from "./core/plugin-cmd.js";
7
7
 
8
+ globalThis.__loomTrace?.("entry", new Error("module imports evaluated"));
8
9
  const args = process.argv.slice(2);
9
10
 
10
11
  // Windows: switch both console codepages to UTF-8 so the box-drawing logo
@@ -45,10 +46,11 @@ const sessionId = sIdx !== -1 ? args[sIdx + 1] : null;
45
46
  const autoMode = args.includes("--auto") || args.includes("-a");
46
47
  const initialPrompt = args.filter((a, i) => !a.startsWith("-") && (sIdx === -1 || i !== sIdx + 1)).join(" ");
47
48
 
49
+ globalThis.__loomTrace("mcp-start", new Error("defaultMcpInstall beginning"));
48
50
  try {
49
51
  defaultMcpInstall();
50
52
  } catch (e) {
51
- globalThis.__loomTrace?.("mcp-install-failed", e);
53
+ globalThis.__loomTrace("mcp-install-failed", e);
52
54
  }
53
55
 
54
56
  if (printMode) {
@@ -62,11 +64,11 @@ if (printMode) {
62
64
  process.exit(resp.type === "error" ? 1 : 0);
63
65
  }
64
66
 
65
- globalThis.__loomTrace?.("render-start");
67
+ globalThis.__loomTrace("render-start", new Error("pre-render"));
66
68
  render(() => <App initialPrompt={initialPrompt} resumeSession={sessionId} autoMode={autoMode} />, {
67
69
  targetFps: 60,
68
70
  useMouse: true,
69
71
  autoFocus: true,
70
72
  exitOnCtrlC: false,
71
73
  });
72
- globalThis.__loomTrace?.("render-returned");
74
+ globalThis.__loomTrace("render-returned", new Error("post-render"));