neural-loom 0.2.53 → 0.2.55

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.
Files changed (97) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/build-manifest.json +3 -3
  3. package/.next/cache/.previewinfo +1 -1
  4. package/.next/cache/.rscinfo +1 -1
  5. package/.next/cache/.tsbuildinfo +1 -1
  6. package/.next/diagnostics/route-bundle-stats.json +2 -2
  7. package/.next/fallback-build-manifest.json +3 -3
  8. package/.next/prerender-manifest.json +3 -3
  9. package/.next/server/app/_global-error.html +1 -1
  10. package/.next/server/app/_global-error.rsc +1 -1
  11. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  12. package/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  13. package/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/.next/server/app/_not-found.html +1 -1
  17. package/.next/server/app/_not-found.rsc +1 -1
  18. package/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  19. package/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  20. package/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  21. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  22. package/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  23. package/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  24. package/.next/server/app/api/context/aider/route.js.nft.json +1 -1
  25. package/.next/server/app/api/context/claude/route.js.nft.json +1 -1
  26. package/.next/server/app/api/context/route.js.nft.json +1 -1
  27. package/.next/server/app/api/context/ssh/route.js.nft.json +1 -1
  28. package/.next/server/app/api/recents/route.js.nft.json +1 -1
  29. package/.next/server/app/api/sessions/inject/route.js.nft.json +1 -1
  30. package/.next/server/app/api/sessions/input/route.js.nft.json +1 -1
  31. package/.next/server/app/api/sessions/launch/route.js.nft.json +1 -1
  32. package/.next/server/app/api/sessions/route.js.nft.json +1 -1
  33. package/.next/server/app/api/sessions/scope/route.js.nft.json +1 -1
  34. package/.next/server/app/api/sessions/start/route.js.nft.json +1 -1
  35. package/.next/server/app/api/sessions/stats/route.js.nft.json +1 -1
  36. package/.next/server/app/api/sessions/stop/route.js.nft.json +1 -1
  37. package/.next/server/app/api/sql/connections/route.js.nft.json +1 -1
  38. package/.next/server/app/api/sql/mcp/route.js.nft.json +1 -1
  39. package/.next/server/app/api/sql/query/route.js.nft.json +1 -1
  40. package/.next/server/app/api/sql/schema/route.js.nft.json +1 -1
  41. package/.next/server/app/index.html +1 -1
  42. package/.next/server/app/index.rsc +3 -3
  43. package/.next/server/app/index.segments/__PAGE__.segment.rsc +3 -3
  44. package/.next/server/app/index.segments/_full.segment.rsc +3 -3
  45. package/.next/server/app/index.segments/_head.segment.rsc +1 -1
  46. package/.next/server/app/index.segments/_index.segment.rsc +1 -1
  47. package/.next/server/app/index.segments/_tree.segment.rsc +2 -2
  48. package/.next/server/app/page/react-loadable-manifest.json +3 -3
  49. package/.next/server/app/page_client-reference-manifest.js +1 -1
  50. package/.next/server/chunks/[root-of-the-server]__0.ptwor._.js +8 -8
  51. package/.next/server/chunks/[root-of-the-server]__0.ptwor._.js.map +1 -1
  52. package/.next/server/chunks/[root-of-the-server]__00l5btc._.js +5 -5
  53. package/.next/server/chunks/[root-of-the-server]__00l5btc._.js.map +1 -1
  54. package/.next/server/chunks/[root-of-the-server]__06men8g._.js +5 -5
  55. package/.next/server/chunks/[root-of-the-server]__06men8g._.js.map +1 -1
  56. package/.next/server/chunks/[root-of-the-server]__0_o7_jj._.js +1 -1
  57. package/.next/server/chunks/[root-of-the-server]__0_o7_jj._.js.map +1 -1
  58. package/.next/server/chunks/[root-of-the-server]__0co.g5k._.js +5 -5
  59. package/.next/server/chunks/[root-of-the-server]__0co.g5k._.js.map +1 -1
  60. package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js +12 -12
  61. package/.next/server/chunks/[root-of-the-server]__0d0pykb._.js.map +1 -1
  62. package/.next/server/chunks/ssr/_0t7oqy6._.js +2 -2
  63. package/.next/server/chunks/ssr/_0t7oqy6._.js.map +1 -1
  64. package/.next/server/middleware-build-manifest.js +3 -3
  65. package/.next/server/pages/404.html +1 -1
  66. package/.next/server/pages/500.html +1 -1
  67. package/.next/server/server-reference-manifest.js +1 -1
  68. package/.next/server/server-reference-manifest.json +1 -1
  69. package/.next/static/chunks/{070hz362~_h8n.js → 0-vb7c~yrtpon.js} +1 -1
  70. package/.next/static/chunks/{0m-_sw1425nkp.css → 0hoyc~vbuqe0t.css} +1 -1
  71. package/.next/static/chunks/0st7_hghhyuv4.js +1 -0
  72. package/.next/static/chunks/0ulfmf9nsz_o-.js +6 -0
  73. package/.next/trace +1 -1
  74. package/.next/trace-build +1 -1
  75. package/README.md +4 -0
  76. package/package.json +1 -1
  77. package/public/ui-audit.html +1509 -0
  78. package/src/app/components/IdeLayout.tsx +37 -1
  79. package/src/app/components/TerminalConsole.tsx +3 -0
  80. package/src/app/page.module.css +55 -0
  81. package/src/app/page.tsx +21 -3
  82. package/src/lib/agents/AgentRunner.ts +74 -0
  83. package/src/lib/agents/AiderRunner.ts +4 -2
  84. package/src/lib/agents/ClaudeRunner.ts +4 -3
  85. package/src/lib/agents/DockerRunner.ts +4 -2
  86. package/src/lib/agents/MockRunner.ts +2 -1
  87. package/src/lib/agents/SSHRunner.ts +4 -2
  88. package/src/lib/agents/ShellRunner.ts +4 -1
  89. package/src/lib/sql/adapters/MssqlAdapter.ts +1 -1
  90. package/src/lib/sql/adapters/MysqlAdapter.ts +1 -1
  91. package/src/lib/sql/adapters/PostgresAdapter.ts +1 -1
  92. package/src/lib/sql/adapters/SqliteAdapter.ts +1 -1
  93. package/.next/static/chunks/0p28yw2f2duy-.js +0 -1
  94. package/.next/static/chunks/0z0d3-6aolefr.js +0 -6
  95. /package/.next/static/{WLQchpoAU3XMEr3Ep5w4b → PtixAwrSwsBc6DJtUuNCf}/_buildManifest.js +0 -0
  96. /package/.next/static/{WLQchpoAU3XMEr3Ep5w4b → PtixAwrSwsBc6DJtUuNCf}/_clientMiddlewareManifest.js +0 -0
  97. /package/.next/static/{WLQchpoAU3XMEr3Ep5w4b → PtixAwrSwsBc6DJtUuNCf}/_ssgManifest.js +0 -0
@@ -6,6 +6,13 @@ import DirectoryBrowserModal from "./DirectoryBrowserModal";
6
6
  import MarkdownPreview from "./MarkdownPreview";
7
7
  import DbExplorer from "./DbExplorer";
8
8
 
9
+ const getModeIcon = (type: string) => {
10
+ if (type === 'mock') return '🧪';
11
+ if (type.includes('-docker')) return '🐳';
12
+ if (type.includes('-ssh')) return '🌐';
13
+ return '💻';
14
+ };
15
+
9
16
  interface FileNode {
10
17
  name: string;
11
18
  path: string;
@@ -67,6 +74,7 @@ interface RunnerStatus {
67
74
  logsCount: number;
68
75
  workspaceRoot?: string;
69
76
  scopedDirs?: string[];
77
+ agentState?: 'idle' | 'thinking' | 'complete' | 'needs-input';
70
78
  }
71
79
 
72
80
  interface IdeLayoutProps {
@@ -1680,6 +1688,34 @@ export default function IdeLayout({ sessionId, workspaceRoot, scopedDirs, onClos
1680
1688
  <span style={{ fontSize: "0.6rem", color: "var(--muted)", backgroundColor: "rgba(255,255,255,0.05)", padding: "1px 4px", borderRadius: "3px" }}>
1681
1689
  {s.type.replace("claude-", "").replace("aider-", "")}
1682
1690
  </span>
1691
+ {s.status === 'running' && s.agentState && (
1692
+ <span
1693
+ style={{
1694
+ fontSize: "0.6rem",
1695
+ padding: "1px 4px",
1696
+ borderRadius: "3px",
1697
+ fontWeight: 600,
1698
+ backgroundColor:
1699
+ s.agentState === 'thinking' ? 'rgba(168, 85, 247, 0.2)' :
1700
+ s.agentState === 'needs-input' ? 'rgba(217, 119, 82, 0.2)' :
1701
+ s.agentState === 'complete' ? 'rgba(16, 185, 129, 0.2)' : 'rgba(255,255,255,0.05)',
1702
+ color:
1703
+ s.agentState === 'thinking' ? '#c084fc' :
1704
+ s.agentState === 'needs-input' ? '#e0825f' :
1705
+ s.agentState === 'complete' ? '#34d399' : 'var(--muted)',
1706
+ border:
1707
+ s.agentState === 'thinking' ? '1px solid rgba(168, 85, 247, 0.3)' :
1708
+ s.agentState === 'needs-input' ? '1px solid rgba(217, 119, 82, 0.3)' :
1709
+ s.agentState === 'complete' ? '1px solid rgba(16, 185, 129, 0.3)' : '1px solid rgba(255,255,255,0.1)',
1710
+ }}
1711
+ title={`Agent state: ${s.agentState}`}
1712
+ >
1713
+ {s.agentState === 'thinking' && `${getModeIcon(s.type)} 💭 thinking`}
1714
+ {s.agentState === 'needs-input' && `${getModeIcon(s.type)} ⚠️ needs input`}
1715
+ {s.agentState === 'complete' && `${getModeIcon(s.type)} ✅ complete`}
1716
+ {s.agentState === 'idle' && `${getModeIcon(s.type)} 💤 idle`}
1717
+ </span>
1718
+ )}
1683
1719
  </div>
1684
1720
  );
1685
1721
  })}
@@ -1921,7 +1957,7 @@ export default function IdeLayout({ sessionId, workspaceRoot, scopedDirs, onClos
1921
1957
  {sessions
1922
1958
  .filter(s => s.id !== sessionId && s.status === 'running')
1923
1959
  .map(s => (
1924
- <option key={s.id} value={s.id}>🖥️|🖥️ Split: {s.name}</option>
1960
+ <option key={s.id} value={s.id}>🖥️|🖥️ Split: {s.name} ({s.agentState || 'idle'})</option>
1925
1961
  ))
1926
1962
  }
1927
1963
  </select>
@@ -48,6 +48,7 @@ export default function TerminalConsole({ sessionId, height = "400px", wsPort =
48
48
  term.loadAddon(fitAddon);
49
49
 
50
50
  term.open(terminalRef.current);
51
+ term.focus();
51
52
 
52
53
  // Monkeypatch to prevent crash during unmount / disposal
53
54
  try {
@@ -144,6 +145,7 @@ export default function TerminalConsole({ sessionId, height = "400px", wsPort =
144
145
  ws.send(JSON.stringify({ type: "handshake", sessionId }));
145
146
  // Send initial dimensions
146
147
  ws.send(JSON.stringify({ type: "resize", cols: term.cols, rows: term.rows }));
148
+ term.focus();
147
149
  };
148
150
 
149
151
  ws.onmessage = (event) => {
@@ -155,6 +157,7 @@ export default function TerminalConsole({ sessionId, height = "400px", wsPort =
155
157
  if (msg.history) {
156
158
  term.write(msg.history);
157
159
  }
160
+ term.focus();
158
161
  } else if (msg.type === "output") {
159
162
  term.write(msg.data);
160
163
  } else if (msg.type === "error") {
@@ -339,3 +339,58 @@
339
339
  width: 100%;
340
340
  }
341
341
 
342
+ .agentStateBadge {
343
+ font-size: 0.65rem;
344
+ padding: 0.15rem 0.4rem;
345
+ border-radius: 4px;
346
+ font-weight: 600;
347
+ text-transform: uppercase;
348
+ letter-spacing: 0.05em;
349
+ display: inline-flex;
350
+ align-items: center;
351
+ gap: 0.25rem;
352
+ margin-right: 0.25rem;
353
+ }
354
+
355
+ .state-thinking {
356
+ background-color: rgba(168, 85, 247, 0.15);
357
+ color: #c084fc;
358
+ border: 1px solid rgba(168, 85, 247, 0.3);
359
+ box-shadow: 0 0 8px rgba(168, 85, 247, 0.2);
360
+ animation: pulse-thinking 2s infinite ease-in-out;
361
+ }
362
+
363
+ .state-needs-input {
364
+ background-color: rgba(217, 119, 82, 0.15);
365
+ color: #e0825f;
366
+ border: 1px solid rgba(217, 119, 82, 0.3);
367
+ box-shadow: 0 0 8px rgba(217, 119, 82, 0.2);
368
+ animation: pulse-attention 1.5s infinite ease-in-out;
369
+ }
370
+
371
+ .state-complete {
372
+ background-color: rgba(16, 185, 129, 0.15);
373
+ color: #34d399;
374
+ border: 1px solid rgba(16, 185, 129, 0.3);
375
+ }
376
+
377
+ .state-idle {
378
+ background-color: rgba(255, 255, 255, 0.05);
379
+ color: var(--muted);
380
+ border: 1px solid rgba(255, 255, 255, 0.1);
381
+ }
382
+
383
+ @keyframes pulse-thinking {
384
+ 0% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0.4); }
385
+ 70% { box-shadow: 0 0 0 5px rgba(168, 85, 247, 0); }
386
+ 100% { box-shadow: 0 0 0 0 rgba(168, 85, 247, 0); }
387
+ }
388
+
389
+ @keyframes pulse-attention {
390
+ 0% { box-shadow: 0 0 0 0 rgba(217, 119, 82, 0.4); }
391
+ 70% { box-shadow: 0 0 0 5px rgba(217, 119, 82, 0); }
392
+ 100% { box-shadow: 0 0 0 0 rgba(217, 119, 82, 0); }
393
+ }
394
+
395
+
396
+
package/src/app/page.tsx CHANGED
@@ -14,8 +14,16 @@ interface RunnerStatus {
14
14
  logsCount: number;
15
15
  workspaceRoot?: string;
16
16
  scopedDirs?: string[];
17
+ agentState?: 'idle' | 'thinking' | 'complete' | 'needs-input';
17
18
  }
18
19
 
20
+ const getModeIcon = (type: string) => {
21
+ if (type === 'mock') return '🧪';
22
+ if (type.includes('-docker')) return '🐳';
23
+ if (type.includes('-ssh')) return '🌐';
24
+ return '💻';
25
+ };
26
+
19
27
  // Dynamically import TerminalConsole to bypass SSR errors
20
28
  const TerminalConsole = dynamic(() => import("./components/TerminalConsole"), {
21
29
  ssr: false,
@@ -355,9 +363,19 @@ export default function Home() {
355
363
  <div key={session.id} className={`${styles.agentCard} card ${activeSessionId === session.id ? styles.activeBorder : ""}`}>
356
364
  <div className={styles.agentHeader}>
357
365
  <span className={styles.agentName}>{session.name}</span>
358
- <span className={`${styles.agentBadge} ${session.status === 'stopped' ? styles.stoppedBadge : ""}`}>
359
- {session.status}
360
- </span>
366
+ <div style={{ display: "flex", gap: "0.35rem", alignItems: "center" }}>
367
+ {session.status === 'running' && session.agentState && (
368
+ <span className={`${styles.agentStateBadge} ${styles['state-' + session.agentState]}`}>
369
+ {session.agentState === 'thinking' && `${getModeIcon(session.type)} 💭 thinking`}
370
+ {session.agentState === 'needs-input' && `${getModeIcon(session.type)} ⚠️ needs input`}
371
+ {session.agentState === 'complete' && `${getModeIcon(session.type)} ✅ complete`}
372
+ {session.agentState === 'idle' && `${getModeIcon(session.type)} 💤 idle`}
373
+ </span>
374
+ )}
375
+ <span className={`${styles.agentBadge} ${session.status === 'stopped' ? styles.stoppedBadge : ""}`}>
376
+ {session.status}
377
+ </span>
378
+ </div>
361
379
  </div>
362
380
  <div className={styles.cardBody}>
363
381
  <p style={{ fontSize: "0.825rem", color: "var(--muted)" }}>
@@ -9,6 +9,7 @@ export interface RunnerStatus {
9
9
  scopedDirs?: string[];
10
10
  lastSyncedWorkspaceFolders?: string[];
11
11
  tokenUsage?: { input: number; output: number; cost: number };
12
+ agentState?: 'idle' | 'thinking' | 'complete' | 'needs-input';
12
13
  }
13
14
 
14
15
  export abstract class AgentRunner {
@@ -22,6 +23,8 @@ export abstract class AgentRunner {
22
23
  scopedDirs?: string[];
23
24
  lastSyncedWorkspaceFolders?: string[];
24
25
  tokenUsage: { input: number; output: number; cost: number } = { input: 0, output: 0, cost: 0 };
26
+ agentState: 'idle' | 'thinking' | 'complete' | 'needs-input' = 'idle';
27
+ private stateTimer: NodeJS.Timeout | null = null;
25
28
 
26
29
  protected parseTokenUsage(data: string): void {
27
30
  const cleanData = data.replace(/\x1b\[[0-9;]*m/g, ""); // Strip ANSI colors
@@ -87,6 +90,77 @@ export abstract class AgentRunner {
87
90
  }
88
91
 
89
92
  protected emitOutput(data: string): void {
93
+ this.updateAgentState(data);
90
94
  this.listeners.forEach(cb => cb(data));
91
95
  }
96
+
97
+ /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
98
+ protected async writeToPty(ptyProcess: any, text: string): Promise<void> {
99
+ if (!ptyProcess) return;
100
+ const isWin = process.platform === "win32";
101
+ if (isWin && text.length > 100) {
102
+ const chunkSize = 128;
103
+ for (let i = 0; i < text.length; i += chunkSize) {
104
+ const chunk = text.slice(i, i + chunkSize);
105
+ ptyProcess.write(chunk);
106
+ await new Promise((resolve) => setTimeout(resolve, 10));
107
+ }
108
+ } else {
109
+ ptyProcess.write(text);
110
+ }
111
+ }
112
+
113
+ protected updateAgentState(newData: string): void {
114
+ if (this.status !== 'running') {
115
+ this.agentState = 'idle';
116
+ return;
117
+ }
118
+
119
+ if (newData.trim().length > 0) {
120
+ this.agentState = 'thinking';
121
+ }
122
+
123
+ if (this.stateTimer) {
124
+ clearTimeout(this.stateTimer);
125
+ }
126
+
127
+ this.stateTimer = setTimeout(() => {
128
+ this.analyzeState();
129
+ }, 800);
130
+ }
131
+
132
+ private analyzeState(): void {
133
+ if (this.status !== 'running') {
134
+ this.agentState = 'idle';
135
+ return;
136
+ }
137
+
138
+ const tailLines = this.logs.slice(-5).join("");
139
+ const cleanTail = tailLines.replace(/\x1b\[[0-9;]*[a-zA-Z]/g, "").trim();
140
+
141
+ const isQuestion =
142
+ /(\[y\/n\]|\(y\/n\)|\?|confirm|allow|should I|would you|press enter|proceed)/i.test(cleanTail);
143
+
144
+ const isPrompt =
145
+ cleanTail.endsWith(">") ||
146
+ cleanTail.endsWith("> ") ||
147
+ /([a-zA-Z0-9_-]+>\s*)$/.test(cleanTail) ||
148
+ cleanTail.endsWith("$") ||
149
+ cleanTail.endsWith("$ ");
150
+
151
+ if (isQuestion) {
152
+ this.agentState = 'needs-input';
153
+ } else if (isPrompt) {
154
+ if (this.agentState === 'thinking') {
155
+ this.agentState = 'complete';
156
+
157
+ if (this.stateTimer) clearTimeout(this.stateTimer);
158
+ this.stateTimer = setTimeout(() => {
159
+ if (this.agentState === 'complete') {
160
+ this.agentState = 'idle';
161
+ }
162
+ }, 5000);
163
+ }
164
+ }
165
+ }
92
166
  }
@@ -291,7 +291,8 @@ export class AiderRunner extends AgentRunner {
291
291
  return;
292
292
  }
293
293
 
294
- this.ptyProcess.write(isRaw ? text : text + "\r");
294
+ this.agentState = 'thinking';
295
+ await this.writeToPty(this.ptyProcess, isRaw ? text : text + "\r");
295
296
  }
296
297
 
297
298
  override resize(cols: number, rows: number): void {
@@ -314,7 +315,8 @@ export class AiderRunner extends AgentRunner {
314
315
  logsCount: this.logs.length,
315
316
  workspaceRoot: this.workspaceRoot,
316
317
  scopedDirs: this.scopedDirs,
317
- tokenUsage: this.tokenUsage
318
+ tokenUsage: this.tokenUsage,
319
+ agentState: this.agentState
318
320
  };
319
321
  }
320
322
  }
@@ -181,8 +181,8 @@ export class ClaudeRunner extends AgentRunner {
181
181
  return;
182
182
  }
183
183
 
184
- // PTY processes require carriage return (\r) to execute the command line
185
- this.ptyProcess.write(isRaw ? text : text + "\r");
184
+ this.agentState = 'thinking';
185
+ await this.writeToPty(this.ptyProcess, isRaw ? text : text + "\r");
186
186
  }
187
187
 
188
188
  override resize(cols: number, rows: number): void {
@@ -205,7 +205,8 @@ export class ClaudeRunner extends AgentRunner {
205
205
  logsCount: this.logs.length,
206
206
  workspaceRoot: this.workspaceRoot,
207
207
  scopedDirs: this.scopedDirs,
208
- tokenUsage: this.tokenUsage
208
+ tokenUsage: this.tokenUsage,
209
+ agentState: this.agentState
209
210
  };
210
211
  }
211
212
  }
@@ -185,7 +185,8 @@ export class DockerRunner extends AgentRunner {
185
185
  return;
186
186
  }
187
187
 
188
- this.ptyProcess.write(isRaw ? text : text + "\r");
188
+ this.agentState = 'thinking';
189
+ await this.writeToPty(this.ptyProcess, isRaw ? text : text + "\r");
189
190
  }
190
191
 
191
192
  override resize(cols: number, rows: number): void {
@@ -208,7 +209,8 @@ export class DockerRunner extends AgentRunner {
208
209
  logsCount: this.logs.length,
209
210
  workspaceRoot: this.workspaceRoot,
210
211
  scopedDirs: this.scopedDirs,
211
- tokenUsage: this.tokenUsage
212
+ tokenUsage: this.tokenUsage,
213
+ agentState: this.agentState
212
214
  };
213
215
  }
214
216
  }
@@ -120,7 +120,8 @@ export class MockRunner extends AgentRunner {
120
120
  status: this.status,
121
121
  createdAt: this.createdAt,
122
122
  logsCount: this.logs.length,
123
- tokenUsage: this.tokenUsage
123
+ tokenUsage: this.tokenUsage,
124
+ agentState: this.agentState
124
125
  };
125
126
  }
126
127
  }
@@ -183,7 +183,8 @@ export class SSHRunner extends AgentRunner {
183
183
  return;
184
184
  }
185
185
 
186
- this.ptyProcess.write(isRaw ? text : text + "\r");
186
+ this.agentState = 'thinking';
187
+ await this.writeToPty(this.ptyProcess, isRaw ? text : text + "\r");
187
188
  }
188
189
 
189
190
  override resize(cols: number, rows: number): void {
@@ -206,7 +207,8 @@ export class SSHRunner extends AgentRunner {
206
207
  logsCount: this.logs.length,
207
208
  workspaceRoot: this.workspaceRoot,
208
209
  scopedDirs: this.scopedDirs,
209
- tokenUsage: this.tokenUsage
210
+ tokenUsage: this.tokenUsage,
211
+ agentState: this.agentState
210
212
  };
211
213
  }
212
214
  }
@@ -129,7 +129,9 @@ export class ShellRunner extends AgentRunner {
129
129
  this.appendLog(`\r\n[Error] Shell process is ${this.status}.\r\n`);
130
130
  return;
131
131
  }
132
- this.ptyProcess.write(isRaw ? text : text + "\r");
132
+
133
+ this.agentState = 'thinking';
134
+ await this.writeToPty(this.ptyProcess, isRaw ? text : text + "\r");
133
135
  }
134
136
 
135
137
  override resize(cols: number, rows: number): void {
@@ -152,6 +154,7 @@ export class ShellRunner extends AgentRunner {
152
154
  logsCount: this.logs.length,
153
155
  workspaceRoot: process.env.ORIGINAL_CWD || process.cwd(),
154
156
  scopedDirs: [],
157
+ agentState: this.agentState
155
158
  };
156
159
  }
157
160
  }
@@ -16,7 +16,7 @@ export class MssqlAdapter extends DbAdapter {
16
16
  try {
17
17
  let mssql;
18
18
  try {
19
- mssql = require("mssql");
19
+ mssql = eval("require")("mssql");
20
20
  } catch (err) {
21
21
  throw new Error(
22
22
  "Microsoft SQL Server driver 'mssql' is not installed. Please run `npm install mssql` in the neural-loom environment."
@@ -16,7 +16,7 @@ export class MysqlAdapter extends DbAdapter {
16
16
  try {
17
17
  let mysql;
18
18
  try {
19
- mysql = require("mysql2/promise");
19
+ mysql = eval("require")("mysql2/promise");
20
20
  } catch (err) {
21
21
  throw new Error(
22
22
  "MySQL driver 'mysql2' is not installed. Please run `npm install mysql2` in the neural-loom environment."
@@ -16,7 +16,7 @@ export class PostgresAdapter extends DbAdapter {
16
16
  try {
17
17
  let ClientClass;
18
18
  try {
19
- const pg = require("pg");
19
+ const pg = eval("require")("pg");
20
20
  ClientClass = pg.Client;
21
21
  } catch (err) {
22
22
  throw new Error(
@@ -32,7 +32,7 @@ export class SqliteAdapter extends DbAdapter {
32
32
  // Lazy load better-sqlite3
33
33
  let Database;
34
34
  try {
35
- Database = require("better-sqlite3");
35
+ Database = eval("require")("better-sqlite3");
36
36
  } catch (err) {
37
37
  throw new Error(
38
38
  "SQLite driver 'better-sqlite3' is not installed. Please run `npm install better-sqlite3` in the neural-loom environment."