loom-agent 1.2.5 → 1.2.7
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 +1 -0
- package/package.json +1 -1
- package/src/core/cli.js +1 -0
- package/src/tui/App.tsx +3 -2
- package/src/tui/components/SplashScreen.tsx +0 -3
- package/src/tui-bootstrap.js +32 -0
- package/src/tui-open.tsx +20 -3
package/bin/loom-tui.js
CHANGED
|
@@ -32,6 +32,7 @@ const entry = path.join(__dirname, '..', 'src', 'tui-bootstrap.js');
|
|
|
32
32
|
// is restored by the bootstrap shim before app code runs.
|
|
33
33
|
const pkgRoot = path.join(__dirname, '..');
|
|
34
34
|
process.env.LOOM_START_CWD = process.cwd();
|
|
35
|
+
process.env.LOOM_BIN_NAME = "loom";
|
|
35
36
|
const bun = findBun();
|
|
36
37
|
|
|
37
38
|
if (bun) {
|
package/package.json
CHANGED
package/src/core/cli.js
CHANGED
|
@@ -565,6 +565,7 @@ if (args.includes('--help') || args.includes('-h')) {
|
|
|
565
565
|
// LOOM_START_CWD restores the user's project dir in tui-bootstrap.js.
|
|
566
566
|
const pkgRoot = path.join(__dirname, '..', '..');
|
|
567
567
|
process.env.LOOM_START_CWD = process.cwd();
|
|
568
|
+
process.env.LOOM_BIN_NAME = "loom";
|
|
568
569
|
const tuiArgs = [tuiEntry];
|
|
569
570
|
if (sessionId) tuiArgs.push('-s', sessionId);
|
|
570
571
|
if (autoMode) tuiArgs.push('--auto');
|
package/src/tui/App.tsx
CHANGED
|
@@ -87,7 +87,8 @@ export function App(props: { initialPrompt?: string; resumeSession?: string; aut
|
|
|
87
87
|
setTimeout(function() {
|
|
88
88
|
console.log("");
|
|
89
89
|
console.log(LOOM_LOGO.join("\n"));
|
|
90
|
-
|
|
90
|
+
const binName = process.env.LOOM_BIN_NAME || "loom";
|
|
91
|
+
console.log(" resume: " + binName + " -s " + sessionId);
|
|
91
92
|
console.log("");
|
|
92
93
|
process.exit(code);
|
|
93
94
|
}, 150);
|
|
@@ -1505,7 +1506,7 @@ export function App(props: { initialPrompt?: string; resumeSession?: string; aut
|
|
|
1505
1506
|
_skillDoneOff = on("turn:end", function(d: any) {
|
|
1506
1507
|
if (d?.skills?.length) showToast("skill handled: " + d.skills.join(", "), "ok");
|
|
1507
1508
|
});
|
|
1508
|
-
(globalThis as any).__loomTrace
|
|
1509
|
+
(globalThis as any).__loomTrace("onMount-done", new Error("mount complete"));
|
|
1509
1510
|
});
|
|
1510
1511
|
onCleanup(function() { persistUi(); if (_skillToastOff) _skillToastOff(); if (_skillDoneOff) _skillDoneOff(); });
|
|
1511
1512
|
|
|
@@ -7,9 +7,6 @@ export function SplashScreen() {
|
|
|
7
7
|
const ui = palette("loom");
|
|
8
8
|
|
|
9
9
|
return (
|
|
10
|
-
// Centered like opencode: the whole block (logo + status + chatbox)
|
|
11
|
-
// floats mid-screen and grows symmetrically around its center as the
|
|
12
|
-
// chatbox lines up.
|
|
13
10
|
<box flexDirection="column" flexGrow={1} alignItems="center" justifyContent="center" backgroundColor={ui.bg}>
|
|
14
11
|
<box flexGrow={1} />
|
|
15
12
|
|
package/src/tui-bootstrap.js
CHANGED
|
@@ -14,6 +14,22 @@ if (process.env.LOOM_START_CWD) {
|
|
|
14
14
|
try { process.chdir(process.env.LOOM_START_CWD); } catch {}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
// Windows consoles default to a legacy codepage where the box-drawing /
|
|
18
|
+
// block glyphs used across the TUI render as "?" garbage, and VT input
|
|
19
|
+
// sequences (arrows, ctrl combos, bracketed paste) may never arrive. Switch
|
|
20
|
+
// both console CPs to UTF-8 before anything renders or reads stdin.
|
|
21
|
+
if (process.platform === "win32") {
|
|
22
|
+
try {
|
|
23
|
+
const { dlopen } = require("bun:ffi");
|
|
24
|
+
const k32 = dlopen("kernel32.dll", {
|
|
25
|
+
SetConsoleOutputCP: { args: ["uint"], returns: "int" },
|
|
26
|
+
SetConsoleCP: { args: ["uint"], returns: "int" },
|
|
27
|
+
});
|
|
28
|
+
k32.symbols.SetConsoleOutputCP(65001);
|
|
29
|
+
k32.symbols.SetConsoleCP(65001);
|
|
30
|
+
} catch {}
|
|
31
|
+
}
|
|
32
|
+
|
|
17
33
|
// Crash black-box: OpenTUI swallows post-render errors, leaving users stuck
|
|
18
34
|
// on the splash with no clue why. Persist every uncaught failure to disk so
|
|
19
35
|
// a frozen TUI can be diagnosed after the fact.
|
|
@@ -29,6 +45,22 @@ function record(kind, err) {
|
|
|
29
45
|
}
|
|
30
46
|
process.on("uncaughtException", (e) => { record("uncaughtException", e); });
|
|
31
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 {} });
|
|
32
64
|
|
|
33
65
|
record("boot", new Error(
|
|
34
66
|
`argv=${JSON.stringify(process.argv.slice(1))} cwd=${process.cwd()} ` +
|
package/src/tui-open.tsx
CHANGED
|
@@ -5,8 +5,24 @@ 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
|
|
|
11
|
+
// Windows: switch both console codepages to UTF-8 so the box-drawing logo
|
|
12
|
+
// and VT input sequences work even when launched without the bootstrap
|
|
13
|
+
// shim (bun run src/tui-open.tsx). No-op elsewhere / if FFI is unavailable.
|
|
14
|
+
if (process.platform === "win32") {
|
|
15
|
+
try {
|
|
16
|
+
const { dlopen } = require("bun:ffi");
|
|
17
|
+
const k32 = dlopen("kernel32.dll", {
|
|
18
|
+
SetConsoleOutputCP: { args: ["uint"], returns: "int" },
|
|
19
|
+
SetConsoleCP: { args: ["uint"], returns: "int" },
|
|
20
|
+
});
|
|
21
|
+
k32.symbols.SetConsoleOutputCP(65001);
|
|
22
|
+
k32.symbols.SetConsoleCP(65001);
|
|
23
|
+
} catch {}
|
|
24
|
+
}
|
|
25
|
+
|
|
10
26
|
if (args.includes("--version") || args.includes("-v")) {
|
|
11
27
|
console.log(`loom-code v${import.meta.require("../package.json").version}`);
|
|
12
28
|
process.exit(0);
|
|
@@ -30,10 +46,11 @@ const sessionId = sIdx !== -1 ? args[sIdx + 1] : null;
|
|
|
30
46
|
const autoMode = args.includes("--auto") || args.includes("-a");
|
|
31
47
|
const initialPrompt = args.filter((a, i) => !a.startsWith("-") && (sIdx === -1 || i !== sIdx + 1)).join(" ");
|
|
32
48
|
|
|
49
|
+
globalThis.__loomTrace("mcp-start", new Error("defaultMcpInstall beginning"));
|
|
33
50
|
try {
|
|
34
51
|
defaultMcpInstall();
|
|
35
52
|
} catch (e) {
|
|
36
|
-
globalThis.__loomTrace
|
|
53
|
+
globalThis.__loomTrace("mcp-install-failed", e);
|
|
37
54
|
}
|
|
38
55
|
|
|
39
56
|
if (printMode) {
|
|
@@ -47,11 +64,11 @@ if (printMode) {
|
|
|
47
64
|
process.exit(resp.type === "error" ? 1 : 0);
|
|
48
65
|
}
|
|
49
66
|
|
|
50
|
-
globalThis.__loomTrace
|
|
67
|
+
globalThis.__loomTrace("render-start", new Error("pre-render"));
|
|
51
68
|
render(() => <App initialPrompt={initialPrompt} resumeSession={sessionId} autoMode={autoMode} />, {
|
|
52
69
|
targetFps: 60,
|
|
53
70
|
useMouse: true,
|
|
54
71
|
autoFocus: true,
|
|
55
72
|
exitOnCtrlC: false,
|
|
56
73
|
});
|
|
57
|
-
globalThis.__loomTrace
|
|
74
|
+
globalThis.__loomTrace("render-returned", new Error("post-render"));
|