@easynet/agent-runtime 1.0.2 → 1.0.4

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 (205) hide show
  1. package/.github/workflows/ci.yml +9 -24
  2. package/.github/workflows/release.yml +38 -26
  3. package/agent-runtime/.github/workflows/ci.yml +69 -0
  4. package/agent-runtime/.github/workflows/release.yml +118 -0
  5. package/agent-runtime/.releaserc.cjs +26 -0
  6. package/agent-runtime/config/agent.deep.yaml +25 -0
  7. package/agent-runtime/config/agent.react.yaml +24 -0
  8. package/agent-runtime/example/basic-usage.ts +49 -0
  9. package/agent-runtime/package-lock.json +7740 -0
  10. package/agent-runtime/package.json +49 -0
  11. package/agent-runtime/pnpm-lock.yaml +3712 -0
  12. package/agent-runtime/scripts/resolve-deps.js +54 -0
  13. package/agent-runtime/src/agents/deep-agent.ts +165 -0
  14. package/agent-runtime/src/agents/react-agent.helpers.ts +227 -0
  15. package/agent-runtime/src/agents/react-agent.ts +584 -0
  16. package/{src → agent-runtime/src/agents}/sub-agent.ts +2 -2
  17. package/agent-runtime/src/cli/args.ts +15 -0
  18. package/agent-runtime/src/cli/event-listener.ts +162 -0
  19. package/agent-runtime/src/cli/interactive.ts +144 -0
  20. package/agent-runtime/src/cli/runtime.ts +31 -0
  21. package/agent-runtime/src/cli/spinner.ts +23 -0
  22. package/agent-runtime/src/cli/terminal-render.ts +322 -0
  23. package/agent-runtime/src/cli/types.ts +33 -0
  24. package/agent-runtime/src/cli.ts +134 -0
  25. package/agent-runtime/src/config/helpers.ts +179 -0
  26. package/agent-runtime/src/config/index.ts +245 -0
  27. package/agent-runtime/src/config/types.ts +62 -0
  28. package/agent-runtime/src/core/context.ts +266 -0
  29. package/agent-runtime/src/index.ts +55 -0
  30. package/agent-runtime/tsconfig.json +18 -0
  31. package/apps/imessagebot/README.md +38 -0
  32. package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/README.md +33 -0
  33. package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/package-lock.json +15257 -0
  34. package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/package.json +55 -0
  35. package/apps/imessagebot/config/agents/deep/agent.yaml +31 -0
  36. package/apps/imessagebot/config/agents/react/agent.yaml +58 -0
  37. package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/README.md +33 -0
  38. package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/package-lock.json +15457 -0
  39. package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/package.json +55 -0
  40. package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/README.md +33 -0
  41. package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/package-lock.json +15257 -0
  42. package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/package.json +62 -0
  43. package/apps/imessagebot/config/agents/shared/memory.yaml +31 -0
  44. package/apps/imessagebot/config/agents/shared/model.yaml +23 -0
  45. package/apps/imessagebot/config/agents/shared/tool.yaml +13 -0
  46. package/apps/imessagebot/config/app.yaml +14 -0
  47. package/apps/imessagebot/package-lock.json +53695 -0
  48. package/apps/imessagebot/package.json +41 -0
  49. package/apps/imessagebot/pnpm-lock.yaml +1589 -0
  50. package/apps/imessagebot/scripts/resolve-deps.js +41 -0
  51. package/apps/imessagebot/scripts/test-llm.mjs +27 -0
  52. package/apps/imessagebot/scripts/validate-tools-config.mjs +174 -0
  53. package/apps/imessagebot/src/config.ts +76 -0
  54. package/apps/imessagebot/src/context.ts +35 -0
  55. package/apps/imessagebot/src/index.ts +17 -0
  56. package/apps/imessagebot/tsconfig.json +18 -0
  57. package/apps/itermbot/.github/workflows/ci.yml +61 -0
  58. package/apps/itermbot/.github/workflows/release.yml +80 -0
  59. package/apps/itermbot/.releaserc.cjs +26 -0
  60. package/apps/itermbot/README.md +82 -0
  61. package/apps/itermbot/config/app.yaml +29 -0
  62. package/apps/itermbot/config/tsconfig.json +18 -0
  63. package/apps/itermbot/macos_disk_usage_agent_plan.md +244 -0
  64. package/apps/itermbot/package-lock.json +53697 -0
  65. package/apps/itermbot/package.json +57 -0
  66. package/apps/itermbot/pnpm-lock.yaml +3966 -0
  67. package/apps/itermbot/scripts/patch-buildin-cache.sh +25 -0
  68. package/apps/itermbot/scripts/resolve-deps.js +41 -0
  69. package/apps/itermbot/scripts/test-llm.mjs +32 -0
  70. package/apps/itermbot/skills/command-explain-and-guard/SKILL.md +39 -0
  71. package/apps/itermbot/skills/command-explain-and-guard/handler.js +86 -0
  72. package/apps/itermbot/skills/disk-usage-investigate/SKILL.md +44 -0
  73. package/apps/itermbot/skills/disk-usage-investigate/handler.js +12 -0
  74. package/apps/itermbot/skills/gpu-ssh-monitor/SKILL.md +64 -0
  75. package/apps/itermbot/skills/repo-triage/SKILL.md +40 -0
  76. package/apps/itermbot/skills/repo-triage/handler.js +56 -0
  77. package/apps/itermbot/skills/test-failure-diagnose/SKILL.md +43 -0
  78. package/apps/itermbot/skills/test-failure-diagnose/handler.js +107 -0
  79. package/apps/itermbot/src/config.ts +95 -0
  80. package/apps/itermbot/src/context.ts +35 -0
  81. package/apps/itermbot/src/index.ts +223 -0
  82. package/apps/itermbot/src/iterm/session-hint.ts +40 -0
  83. package/apps/itermbot/src/iterm/target-routing.ts +419 -0
  84. package/apps/itermbot/src/startup/colors.ts +317 -0
  85. package/apps/itermbot/src/startup/diagnostics.ts +97 -0
  86. package/apps/itermbot/src/startup/ui.ts +141 -0
  87. package/config/agent.deep.yaml +25 -0
  88. package/config/agent.react.yaml +24 -0
  89. package/dist/agents/deep-agent.d.ts +37 -0
  90. package/dist/agents/deep-agent.d.ts.map +1 -0
  91. package/dist/agents/deep-agent.js +115 -0
  92. package/dist/agents/deep-agent.js.map +1 -0
  93. package/dist/agents/react-agent.d.ts +40 -0
  94. package/dist/agents/react-agent.d.ts.map +1 -0
  95. package/dist/agents/react-agent.helpers.d.ts +40 -0
  96. package/dist/agents/react-agent.helpers.d.ts.map +1 -0
  97. package/dist/agents/react-agent.helpers.js +196 -0
  98. package/dist/agents/react-agent.helpers.js.map +1 -0
  99. package/dist/agents/react-agent.js +400 -0
  100. package/dist/agents/react-agent.js.map +1 -0
  101. package/dist/agents/sub-agent.d.ts +34 -0
  102. package/dist/agents/sub-agent.d.ts.map +1 -0
  103. package/dist/agents/sub-agent.js +53 -0
  104. package/dist/agents/sub-agent.js.map +1 -0
  105. package/dist/cli/args.d.ts +8 -0
  106. package/dist/cli/args.d.ts.map +1 -0
  107. package/dist/cli/args.js +9 -0
  108. package/dist/cli/args.js.map +1 -0
  109. package/dist/cli/event-listener.d.ts +3 -0
  110. package/dist/cli/event-listener.d.ts.map +1 -0
  111. package/dist/cli/event-listener.js +131 -0
  112. package/dist/cli/event-listener.js.map +1 -0
  113. package/dist/cli/interactive.d.ts +4 -0
  114. package/dist/cli/interactive.d.ts.map +1 -0
  115. package/dist/cli/interactive.js +118 -0
  116. package/dist/cli/interactive.js.map +1 -0
  117. package/dist/cli/runtime.d.ts +8 -0
  118. package/dist/cli/runtime.d.ts.map +1 -0
  119. package/dist/cli/runtime.js +27 -0
  120. package/dist/cli/runtime.js.map +1 -0
  121. package/dist/cli/spinner.d.ts +2 -0
  122. package/dist/cli/spinner.d.ts.map +1 -0
  123. package/dist/cli/spinner.js +22 -0
  124. package/dist/cli/spinner.js.map +1 -0
  125. package/dist/cli/terminal-render.d.ts +7 -0
  126. package/dist/cli/terminal-render.d.ts.map +1 -0
  127. package/dist/cli/terminal-render.js +282 -0
  128. package/dist/cli/terminal-render.js.map +1 -0
  129. package/dist/cli/types.d.ts +29 -0
  130. package/dist/cli/types.d.ts.map +1 -0
  131. package/dist/cli/types.js +3 -0
  132. package/dist/cli/types.js.map +1 -0
  133. package/dist/cli.d.ts +4 -41
  134. package/dist/cli.d.ts.map +1 -1
  135. package/dist/cli.js +84 -588
  136. package/dist/cli.js.map +1 -1
  137. package/dist/config/helpers.d.ts +6 -0
  138. package/dist/config/helpers.d.ts.map +1 -0
  139. package/dist/config/helpers.js +164 -0
  140. package/dist/config/helpers.js.map +1 -0
  141. package/dist/config/index.d.ts +15 -0
  142. package/dist/config/index.d.ts.map +1 -0
  143. package/dist/config/index.js +160 -0
  144. package/dist/config/index.js.map +1 -0
  145. package/dist/config/types.d.ts +57 -0
  146. package/dist/config/types.d.ts.map +1 -0
  147. package/dist/config/types.js +2 -0
  148. package/dist/config/types.js.map +1 -0
  149. package/dist/context.d.ts +8 -69
  150. package/dist/context.d.ts.map +1 -1
  151. package/dist/context.js +44 -24
  152. package/dist/context.js.map +1 -1
  153. package/dist/core/context.d.ts +66 -0
  154. package/dist/core/context.d.ts.map +1 -0
  155. package/dist/core/context.js +149 -0
  156. package/dist/core/context.js.map +1 -0
  157. package/dist/deep-agent.d.ts +5 -2
  158. package/dist/deep-agent.d.ts.map +1 -1
  159. package/dist/deep-agent.js +44 -11
  160. package/dist/deep-agent.js.map +1 -1
  161. package/dist/index.d.ts +6 -6
  162. package/dist/index.d.ts.map +1 -1
  163. package/dist/index.js +6 -6
  164. package/dist/index.js.map +1 -1
  165. package/dist/middleware/malformed-tool-call-middleware.d.ts +8 -0
  166. package/dist/middleware/malformed-tool-call-middleware.d.ts.map +1 -0
  167. package/dist/middleware/malformed-tool-call-middleware.js +191 -0
  168. package/dist/middleware/malformed-tool-call-middleware.js.map +1 -0
  169. package/dist/react-agent.d.ts +2 -2
  170. package/dist/react-agent.d.ts.map +1 -1
  171. package/dist/react-agent.js +28 -9
  172. package/dist/react-agent.js.map +1 -1
  173. package/package.json +1 -1
  174. package/scripts/resolve-deps.js +54 -0
  175. package/src/agents/deep-agent.ts +165 -0
  176. package/src/agents/react-agent.helpers.ts +227 -0
  177. package/src/agents/react-agent.ts +584 -0
  178. package/src/agents/sub-agent.ts +82 -0
  179. package/src/cli/args.ts +15 -0
  180. package/src/cli/event-listener.ts +162 -0
  181. package/src/cli/interactive.ts +144 -0
  182. package/src/cli/runtime.ts +31 -0
  183. package/src/cli/spinner.ts +23 -0
  184. package/src/cli/terminal-render.ts +322 -0
  185. package/src/cli/types.ts +33 -0
  186. package/src/cli.ts +91 -702
  187. package/src/config/helpers.ts +179 -0
  188. package/src/config/index.ts +245 -0
  189. package/src/config/types.ts +62 -0
  190. package/src/core/context.ts +266 -0
  191. package/src/index.ts +13 -11
  192. package/src/middleware/malformed-tool-call-middleware.ts +239 -0
  193. package/src/types/markdown-it-terminal.d.ts +4 -0
  194. package/src/types/marked-terminal.d.ts +16 -0
  195. package/dist/config.d.ts +0 -86
  196. package/dist/config.d.ts.map +0 -1
  197. package/dist/config.js +0 -84
  198. package/dist/config.js.map +0 -1
  199. package/src/config.ts +0 -177
  200. package/src/context.ts +0 -247
  201. package/src/deep-agent.ts +0 -104
  202. package/src/react-agent.ts +0 -576
  203. /package/{src → agent-runtime/src/middleware}/malformed-tool-call-middleware.ts +0 -0
  204. /package/{src → agent-runtime/src/types}/markdown-it-terminal.d.ts +0 -0
  205. /package/{src → agent-runtime/src/types}/marked-terminal.d.ts +0 -0
@@ -0,0 +1,317 @@
1
+ /**
2
+ * Startup panel coloring for iTermBot.
3
+ *
4
+ * Sets distinct background + foreground colors on the chat panel and
5
+ * target panels within the **current tab**, using a professional
6
+ * light-on-dark scheme for both.
7
+ *
8
+ * Identifies the chat panel by matching process TTY against session TTY.
9
+ *
10
+ * Called from the onReady hook — failures are non-fatal.
11
+ */
12
+ import { execFileSync } from "node:child_process";
13
+ import {
14
+ itermListCurrentWindowSessions,
15
+ itermSplitPane,
16
+ itermSetSessionColors,
17
+ } from "@easynet/agent-tool-buildin/iterm";
18
+
19
+ /* ------------------------------------------------------------------ */
20
+ /* Color scheme */
21
+ /* ------------------------------------------------------------------ */
22
+
23
+ // Chat panel: soft slate-blue background, light silver text
24
+ export const CHAT_BG = "#1E2D3D";
25
+ export const CHAT_FG = "#D4D7DC";
26
+
27
+ // Target panel: dark warm charcoal background, soft warm white text
28
+ export const TARGET_BG = "#2A2A2A";
29
+ export const TARGET_FG = "#E8E0D4";
30
+
31
+ /* ------------------------------------------------------------------ */
32
+
33
+ interface SessionInfo {
34
+ windowId?: number;
35
+ tabIndex?: number;
36
+ sessionId?: string;
37
+ tty?: string;
38
+ isCurrentSession?: boolean;
39
+ isCurrentTab?: boolean;
40
+ }
41
+
42
+ export interface SessionColorSnapshot {
43
+ windowId: number;
44
+ tabIndex: number;
45
+ sessionId: string;
46
+ background: [number, number, number];
47
+ foreground: [number, number, number];
48
+ }
49
+
50
+ function quoteAppleScriptString(input: string): string {
51
+ return `"${input.replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
52
+ }
53
+
54
+ function runOsaScriptSync(lines: string[]): string {
55
+ const args: string[] = [];
56
+ for (const line of lines) {
57
+ args.push("-e", line);
58
+ }
59
+ return execFileSync("osascript", args, {
60
+ encoding: "utf-8",
61
+ timeout: 3000,
62
+ stdio: ["ignore", "pipe", "pipe"],
63
+ }).trim();
64
+ }
65
+
66
+ function parseColorTuple(raw: string): [number, number, number] | null {
67
+ const values = raw
68
+ .split(",")
69
+ .map((v) => Number(v.trim()))
70
+ .filter((v) => Number.isFinite(v));
71
+ if (values.length < 3) return null;
72
+ return [values[0]!, values[1]!, values[2]!];
73
+ }
74
+
75
+ function captureSessionColorsSync(args: {
76
+ windowId: number;
77
+ tabIndex: number;
78
+ sessionId: string;
79
+ }): SessionColorSnapshot | null {
80
+ try {
81
+ const sid = quoteAppleScriptString(args.sessionId);
82
+ const script = [
83
+ 'tell application "iTerm"',
84
+ `set targetWindow to first window whose id is ${Math.trunc(args.windowId)}`,
85
+ `set targetTab to tab ${Math.max(1, Math.trunc(args.tabIndex))} of targetWindow`,
86
+ "set targetSession to missing value",
87
+ "try",
88
+ `set targetSession to first session of targetTab whose unique id is ${sid}`,
89
+ "on error",
90
+ `set targetSession to first session of targetTab whose id is ${sid}`,
91
+ "end try",
92
+ "set bg to background color of targetSession",
93
+ "set fg to foreground color of targetSession",
94
+ "return (item 1 of bg as text) & \",\" & (item 2 of bg as text) & \",\" & (item 3 of bg as text) & \"|\" & (item 1 of fg as text) & \",\" & (item 2 of fg as text) & \",\" & (item 3 of fg as text)",
95
+ "end tell",
96
+ ];
97
+ const out = runOsaScriptSync(script);
98
+ const [bgRaw, fgRaw] = out.split("|");
99
+ const bg = parseColorTuple(bgRaw ?? "");
100
+ const fg = parseColorTuple(fgRaw ?? "");
101
+ if (!bg || !fg) return null;
102
+ return {
103
+ windowId: args.windowId,
104
+ tabIndex: args.tabIndex,
105
+ sessionId: args.sessionId,
106
+ background: bg,
107
+ foreground: fg,
108
+ };
109
+ } catch {
110
+ return null;
111
+ }
112
+ }
113
+
114
+ export function captureSessionColorsByIdSync(args: {
115
+ windowId: number;
116
+ tabIndex: number;
117
+ sessionId: string;
118
+ }): SessionColorSnapshot | null {
119
+ return captureSessionColorsSync(args);
120
+ }
121
+
122
+ export function restoreSessionColorsSync(snapshots: SessionColorSnapshot[]): void {
123
+ for (const s of snapshots) {
124
+ try {
125
+ const sid = quoteAppleScriptString(s.sessionId);
126
+ const [br, bg, bb] = s.background;
127
+ const [fr, fg, fb] = s.foreground;
128
+ const script = [
129
+ 'tell application "iTerm"',
130
+ `set targetWindow to first window whose id is ${Math.trunc(s.windowId)}`,
131
+ `set targetTab to tab ${Math.max(1, Math.trunc(s.tabIndex))} of targetWindow`,
132
+ "set targetSession to missing value",
133
+ "try",
134
+ `set targetSession to first session of targetTab whose unique id is ${sid}`,
135
+ "on error",
136
+ `set targetSession to first session of targetTab whose id is ${sid}`,
137
+ "end try",
138
+ `set background color of targetSession to {${br}, ${bg}, ${bb}}`,
139
+ `set foreground color of targetSession to {${fr}, ${fg}, ${fb}}`,
140
+ "end tell",
141
+ ];
142
+ runOsaScriptSync(script);
143
+ } catch {
144
+ // ignore restore failures during process shutdown
145
+ }
146
+ }
147
+ }
148
+
149
+ /**
150
+ * Walk up the process tree to find the controlling TTY.
151
+ */
152
+ function findProcessTty(): string | null {
153
+ try {
154
+ let pid = process.pid;
155
+ for (let i = 0; i < 10; i++) {
156
+ const line = execFileSync("ps", ["-o", "ppid=,tty=", "-p", String(pid)], {
157
+ encoding: "utf-8",
158
+ timeout: 3000,
159
+ }).trim();
160
+ const parts = line.split(/\s+/);
161
+ const ppid = Number(parts[0]);
162
+ const tty = parts[1];
163
+ if (tty && tty !== "??" && tty !== "?") {
164
+ return `/dev/${tty}`;
165
+ }
166
+ if (!ppid || ppid <= 1) break;
167
+ pid = ppid;
168
+ }
169
+ } catch {
170
+ // ignore
171
+ }
172
+ return null;
173
+ }
174
+
175
+ export interface StartupResult {
176
+ chatSessionId: string | null;
177
+ targetSessionId: string | null;
178
+ windowId: number | null;
179
+ tabIndex: number | null;
180
+ colorSnapshots: SessionColorSnapshot[];
181
+ }
182
+
183
+ export async function applyStartupPanelColors(): Promise<StartupResult> {
184
+ const empty: StartupResult = {
185
+ chatSessionId: null,
186
+ targetSessionId: null,
187
+ windowId: null,
188
+ tabIndex: null,
189
+ colorSnapshots: [],
190
+ };
191
+
192
+ const myTty = findProcessTty();
193
+ const { result } = await itermListCurrentWindowSessions();
194
+
195
+ if (result.count === 0) return empty;
196
+
197
+ let sessions = result.sessions as SessionInfo[];
198
+
199
+ let chatSession = myTty
200
+ ? sessions.find((s) => s.tty === myTty)
201
+ : sessions.find((s) => s.isCurrentSession);
202
+
203
+ if (!chatSession) {
204
+ console.error(
205
+ `startup-colors: could not identify chat session (tty=${myTty}), skipping`,
206
+ );
207
+ return empty;
208
+ }
209
+
210
+ let currentTabIndex = chatSession.tabIndex!;
211
+ let windowId = (result.windowId ?? chatSession.windowId)!;
212
+ const chatSessionId = chatSession.sessionId;
213
+
214
+ let sameTabSessions = sessions.filter(
215
+ (s) => s.tabIndex === currentTabIndex,
216
+ );
217
+ let targetSessions = sameTabSessions.filter(
218
+ (s) => s.sessionId !== chatSessionId,
219
+ );
220
+
221
+ // If only chat panel exists, split once to create target panel on startup.
222
+ if (sameTabSessions.length === 1 && chatSessionId) {
223
+ try {
224
+ await itermSplitPane({
225
+ windowId,
226
+ tabIndex: currentTabIndex,
227
+ sessionId: chatSessionId,
228
+ direction: "vertical",
229
+ activate: false,
230
+ });
231
+
232
+ const refreshed = await itermListCurrentWindowSessions();
233
+ sessions = refreshed.result.sessions as SessionInfo[];
234
+ const preservedChat = sessions.find((s) => s.sessionId === chatSessionId);
235
+ if (preservedChat) {
236
+ chatSession = preservedChat;
237
+ }
238
+ currentTabIndex = chatSession.tabIndex ?? currentTabIndex;
239
+ windowId = (refreshed.result.windowId ?? chatSession.windowId ?? windowId)!;
240
+ sameTabSessions = sessions.filter((s) => s.tabIndex === currentTabIndex);
241
+ targetSessions = sameTabSessions.filter((s) => s.sessionId !== chatSessionId);
242
+ } catch (err) {
243
+ console.error(
244
+ "startup-colors: failed to auto-split single panel:",
245
+ err instanceof Error ? err.message : err,
246
+ );
247
+ }
248
+ }
249
+
250
+ const selectedTarget = targetSessions[0] ?? null;
251
+
252
+ const startupResult: StartupResult = {
253
+ chatSessionId: chatSession.sessionId ?? null,
254
+ targetSessionId: selectedTarget?.sessionId ?? null,
255
+ windowId,
256
+ tabIndex: currentTabIndex,
257
+ colorSnapshots: [],
258
+ };
259
+
260
+ const sessionsToSnapshot = [
261
+ chatSession,
262
+ ...(selectedTarget ? [selectedTarget] : []),
263
+ ].filter((s): s is Required<Pick<SessionInfo, "sessionId">> & SessionInfo => Boolean(s.sessionId));
264
+
265
+ const seen = new Set<string>();
266
+ for (const s of sessionsToSnapshot) {
267
+ if (!s.sessionId || seen.has(s.sessionId)) continue;
268
+ seen.add(s.sessionId);
269
+ const snapshot = captureSessionColorsSync({
270
+ windowId,
271
+ tabIndex: currentTabIndex,
272
+ sessionId: s.sessionId,
273
+ });
274
+ if (snapshot) {
275
+ startupResult.colorSnapshots.push(snapshot);
276
+ }
277
+ }
278
+
279
+ const tasks: Promise<unknown>[] = [];
280
+
281
+ if (chatSession.sessionId) {
282
+ tasks.push(
283
+ itermSetSessionColors({
284
+ windowId,
285
+ tabIndex: currentTabIndex,
286
+ sessionId: chatSession.sessionId,
287
+ backgroundHex: CHAT_BG,
288
+ foregroundHex: CHAT_FG,
289
+ }),
290
+ );
291
+ }
292
+
293
+ if (selectedTarget?.sessionId) {
294
+ tasks.push(
295
+ itermSetSessionColors({
296
+ windowId,
297
+ tabIndex: currentTabIndex,
298
+ sessionId: selectedTarget.sessionId,
299
+ backgroundHex: TARGET_BG,
300
+ foregroundHex: TARGET_FG,
301
+ }),
302
+ );
303
+ }
304
+
305
+ const results = await Promise.allSettled(tasks);
306
+
307
+ for (const r of results) {
308
+ if (r.status === "rejected") {
309
+ console.error(
310
+ "startup-colors: failed to set color on a session:",
311
+ r.reason?.message ?? r.reason,
312
+ );
313
+ }
314
+ }
315
+
316
+ return startupResult;
317
+ }
@@ -0,0 +1,97 @@
1
+ import { existsSync } from "node:fs";
2
+ import { dirname, resolve } from "node:path";
3
+ import { loadYamlFile } from "@easynet/agent-common";
4
+ import { formatLogPath, resolveConfigPath } from "./ui.js";
5
+
6
+ export async function getLlmSelectionLabel(modelsPath: string): Promise<string> {
7
+ try {
8
+ const raw = await loadYamlFile<Record<string, unknown>>(modelsPath);
9
+ const spec = raw?.spec && typeof raw.spec === "object" && !Array.isArray(raw.spec)
10
+ ? (raw.spec as Record<string, unknown>)
11
+ : undefined;
12
+ const llm = ((spec?.llm ?? raw?.llm) ?? null) as Record<string, unknown> | null;
13
+ if (!llm) return "name=unknown, model=unknown";
14
+ const selectedName =
15
+ typeof llm.default === "string" && llm.default.trim().length > 0
16
+ ? llm.default.trim()
17
+ : "unknown";
18
+ const selected = llm[selectedName];
19
+ const selectedRec =
20
+ typeof selected === "object" && selected !== null
21
+ ? (selected as Record<string, unknown>)
22
+ : null;
23
+ const model =
24
+ selectedRec && typeof selectedRec.model === "string" && selectedRec.model.trim().length > 0
25
+ ? selectedRec.model.trim()
26
+ : "unknown";
27
+ return `name=${selectedName}, model=${model}`;
28
+ } catch {
29
+ return "name=unknown, model=unknown";
30
+ }
31
+ }
32
+
33
+ export async function getSkillsPathLabel(config: unknown, agentName: string): Promise<string> {
34
+ const app = (config as { app?: unknown } | null)?.app as
35
+ | { agent?: Record<string, { skills?: { ref?: string } }> }
36
+ | undefined;
37
+ const firstAgent = app?.agent ? Object.values(app.agent)[0] : undefined;
38
+ const agent = app?.agent?.[agentName] ?? firstAgent;
39
+ const skillsConfigPathRaw = agent?.skills?.ref;
40
+ if (!skillsConfigPathRaw || typeof skillsConfigPathRaw !== "string") {
41
+ const localSkillsDir = resolve(process.cwd(), "skills");
42
+ if (existsSync(localSkillsDir)) {
43
+ return `skills=auto(${formatLogPath(localSkillsDir)})`;
44
+ }
45
+ return "skills=auto(module-default)";
46
+ }
47
+ const skillsConfigPath = resolveConfigPath(skillsConfigPathRaw);
48
+ try {
49
+ const raw = await loadYamlFile<Record<string, unknown>>(skillsConfigPath);
50
+ const spec = (raw?.spec && typeof raw.spec === "object" && !Array.isArray(raw.spec))
51
+ ? (raw.spec as Record<string, unknown>)
52
+ : undefined;
53
+ const skillsDirRaw = typeof spec?.path === "string"
54
+ ? spec.path
55
+ : (typeof raw?.path === "string" ? raw.path : "");
56
+ if (!skillsDirRaw) return `${formatLogPath(skillsConfigPath)} -> (unknown)`;
57
+ const skillsDir = resolve(dirname(skillsConfigPath), skillsDirRaw);
58
+ return `${formatLogPath(skillsConfigPath)} -> ${formatLogPath(skillsDir)}`;
59
+ } catch {
60
+ return `${formatLogPath(skillsConfigPath)} -> (unreadable)`;
61
+ }
62
+ }
63
+
64
+ function extractLlmText(output: unknown): string {
65
+ const content = (output as { content?: unknown } | null)?.content;
66
+ if (typeof content === "string") return content.trim();
67
+ if (Array.isArray(content)) {
68
+ return content
69
+ .map((part) => {
70
+ if (typeof part === "string") return part;
71
+ if (typeof part === "object" && part && "text" in part) {
72
+ const text = (part as { text?: unknown }).text;
73
+ return typeof text === "string" ? text : "";
74
+ }
75
+ return "";
76
+ })
77
+ .join(" ")
78
+ .trim();
79
+ }
80
+ return "";
81
+ }
82
+
83
+ export async function runLlmHealthCheck(llm: { invoke: (input: string) => Promise<unknown> }): Promise<string> {
84
+ const timeoutMs = Number(process.env.ITERMBOT_LLM_HEALTHCHECK_TIMEOUT_MS ?? "12000");
85
+ const timeout = Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 12000;
86
+
87
+ const invokePromise = llm.invoke("Health check: reply with OK only.");
88
+ const timeoutPromise = new Promise<never>((_, reject) => {
89
+ setTimeout(() => reject(new Error(`LLM health check timeout (${timeout}ms)`)), timeout);
90
+ });
91
+ const output = await Promise.race([invokePromise, timeoutPromise]);
92
+ const text = extractLlmText(output);
93
+ if (!text) {
94
+ throw new Error("LLM health check returned empty response");
95
+ }
96
+ return text.length > 32 ? `${text.slice(0, 32)}...` : text;
97
+ }
@@ -0,0 +1,141 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { dirname, relative, resolve } from "node:path";
3
+ import { fileURLToPath } from "node:url";
4
+
5
+ export function toErrorMessage(error: unknown): string {
6
+ return error instanceof Error ? error.message : String(error);
7
+ }
8
+
9
+ export function formatLogPath(pathValue: string): string {
10
+ const trimmed = pathValue.trim();
11
+ if (!trimmed) return "(unknown)";
12
+ const rel = relative(process.cwd(), trimmed);
13
+ if (!rel || rel.startsWith("..")) return trimmed;
14
+ return rel;
15
+ }
16
+
17
+ export function resolveConfigPath(pathValue: string): string {
18
+ return pathValue.startsWith("/") ? pathValue : resolve(process.cwd(), pathValue);
19
+ }
20
+
21
+ function formatDurationMs(durationMs: number | null): string {
22
+ return durationMs === null ? "" : ` (${durationMs}ms)`;
23
+ }
24
+
25
+ export function clearStartupNoise(): void {
26
+ if (!process.stdout.isTTY) return;
27
+ process.stdout.write("\x1b[2J\x1b[H");
28
+ }
29
+
30
+ export function printStartupBanner(): void {
31
+ const lines = [
32
+ " _ _____ ____ _ ",
33
+ " (_)_ _|__ _ __ _ __ ___ | __ ) ___ | |_ ",
34
+ " | | | |/ _ \\ '__| '_ ` _ \\| _ \\ / _ \\| __|",
35
+ " | | | | __/ | | | | | | | |_) | (_) | |_ ",
36
+ " |_| |_|\\___|_| |_| |_| |_|____/ \\___/ \\__|",
37
+ " iTermBot ",
38
+ ];
39
+ console.log("--------------------------------------------------------------------------------------------------");
40
+ console.log(`\n${lines.join("\n")}`);
41
+ console.log(" Observe the terminal. Act with precision.\n");
42
+ }
43
+
44
+ export function getAppVersion(): string {
45
+ try {
46
+ const currentFile = fileURLToPath(import.meta.url);
47
+ const packageJsonPath = resolve(dirname(currentFile), "../package.json");
48
+ const parsed = JSON.parse(readFileSync(packageJsonPath, "utf8")) as { version?: unknown };
49
+ return typeof parsed.version === "string" ? parsed.version : "unknown";
50
+ } catch {
51
+ return "unknown";
52
+ }
53
+ }
54
+
55
+ export function printStartupSummary(args: { version: string }): void {
56
+ console.log("\n--------------------------------------------------------------------------------------------------");
57
+ console.log(`Version : v${args.version}`);
58
+ console.log(`Workspace : ${process.cwd()}`);
59
+ console.log("");
60
+ console.log("Commands : list tools, list skills, exit");
61
+ console.log("--------------------------------------------------------------------------------------------------\n");
62
+ }
63
+
64
+ export class StartupProgressRenderer {
65
+ private readonly isDynamic = Boolean(process.stdout.isTTY);
66
+ private readonly frames = ["⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏"];
67
+ private readonly lineByStep = new Map<string, number>();
68
+ private readonly timerByStep = new Map<string, NodeJS.Timeout>();
69
+ private readonly frameIndexByStep = new Map<string, number>();
70
+ private lineCount = 0;
71
+
72
+ start(stepId: string, title: string): void {
73
+ const baseLabel = `[startup] ${title}`;
74
+ if (!this.isDynamic) {
75
+ console.log(`${baseLabel} ...`);
76
+ return;
77
+ }
78
+ const lineIndex = this.lineCount;
79
+ this.lineByStep.set(stepId, lineIndex);
80
+ this.frameIndexByStep.set(stepId, 0);
81
+ this.lineCount += 1;
82
+ process.stdout.write(`\r${baseLabel} ${this.frames[0]}\n`);
83
+ const timer = setInterval(() => {
84
+ const current = this.frameIndexByStep.get(stepId);
85
+ if (current === undefined) return;
86
+ const next = (current + 1) % this.frames.length;
87
+ this.frameIndexByStep.set(stepId, next);
88
+ this.renderLine(stepId, `${baseLabel} ${this.frames[next]}`);
89
+ }, 80);
90
+ this.timerByStep.set(stepId, timer);
91
+ }
92
+
93
+ complete(stepId: string, title: string, ok: boolean, detail: string, elapsedMs: number): void {
94
+ const baseLabel = `[startup] ${title}`;
95
+ const mark = ok ? "✅" : "✖";
96
+ const detailPart = detail.trim().length > 0 ? ` ${detail}` : "";
97
+ const finalLine = `${mark} ${baseLabel}${detailPart}${formatDurationMs(elapsedMs)}`;
98
+ const timer = this.timerByStep.get(stepId);
99
+ if (timer) {
100
+ clearInterval(timer);
101
+ this.timerByStep.delete(stepId);
102
+ }
103
+ this.frameIndexByStep.delete(stepId);
104
+ if (!this.isDynamic) {
105
+ console.log(finalLine);
106
+ return;
107
+ }
108
+ this.renderLine(stepId, finalLine);
109
+ }
110
+
111
+ private renderLine(stepId: string, line: string): void {
112
+ const lineIndex = this.lineByStep.get(stepId);
113
+ if (lineIndex === undefined) return;
114
+ const up = this.lineCount - lineIndex;
115
+ if (up <= 0) return;
116
+ process.stdout.write(`\x1b[${up}A\r\x1b[2K${line}\x1b[${up}B\r`);
117
+ }
118
+ }
119
+
120
+ export async function runStartupStep<T>(
121
+ progress: StartupProgressRenderer,
122
+ title: string,
123
+ fn: () => Promise<T> | T,
124
+ formatResult?: (result: T) => string,
125
+ ): Promise<T> {
126
+ const stepId = `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
127
+ const startedAt = Date.now();
128
+ progress.start(stepId, title);
129
+
130
+ try {
131
+ const result = await fn();
132
+ const detail = formatResult ? formatResult(result) : "";
133
+ const elapsed = Date.now() - startedAt;
134
+ progress.complete(stepId, title, true, detail, elapsed);
135
+ return result;
136
+ } catch (error) {
137
+ const elapsed = Date.now() - startedAt;
138
+ progress.complete(stepId, title, false, toErrorMessage(error), elapsed);
139
+ throw error;
140
+ }
141
+ }
@@ -0,0 +1,25 @@
1
+ apiVersion: easynet.world/v1
2
+ kind: AgentConfig
3
+ metadata:
4
+ name: runtime-deep-default
5
+ spec:
6
+ systemPrompt: |
7
+ You are an assistant running in Deep Agent mode.
8
+ Domain rules are provided by app-level prompt templates.
9
+
10
+ ## Execution Rules
11
+ - Solve tasks in clear multi-step order.
12
+ - Use available tools as the source of truth.
13
+ - Prefer low-cost actions first; escalate only when needed.
14
+
15
+ ## Response Rules
16
+ - Keep responses concise, structured, and evidence-based.
17
+ - Do not invent facts not present in observations.
18
+ - Keep internal reasoning private.
19
+
20
+ ## Memory Rules
21
+ - Use `thread` for session context and transient details.
22
+ - Use `cross_thread` for durable preferences/facts.
23
+ - Never store secrets.
24
+ recursionLimit: 8
25
+ memoriesPath: /memories/
@@ -0,0 +1,24 @@
1
+ apiVersion: easynet.world/v1
2
+ kind: AgentConfig
3
+ metadata:
4
+ name: runtime-react-default
5
+ spec:
6
+ systemPrompt: |
7
+ You are an assistant running in ReAct mode.
8
+ Domain rules are provided by app-level prompt templates.
9
+
10
+ ## Tool Calls
11
+ - When taking an action, output exactly one tool call line: `toolName({ ... })`.
12
+ - The parentheses must contain exactly one valid JSON object.
13
+ - No extra wrapper text around tool-call JSON.
14
+
15
+ ## Response Rules
16
+ - Be concise, structured, and evidence-based.
17
+ - Do not invent facts not present in tool outputs.
18
+ - Keep internal reasoning private.
19
+
20
+ ## Memory Rules
21
+ - Use `thread` for session context and transient details.
22
+ - Use `cross_thread` for durable preferences/facts.
23
+ - Never store secrets.
24
+ maxSteps: 40
@@ -0,0 +1,37 @@
1
+ import type { BaseAgentConfig, BotContext } from "../core/context.js";
2
+ export interface DeepAgentRuntime {
3
+ agent: unknown;
4
+ run: (userMessage: string) => Promise<{
5
+ text: string;
6
+ messages?: unknown;
7
+ }>;
8
+ }
9
+ export interface DeepAgentOptions {
10
+ agentName?: string;
11
+ systemPrompt?: string;
12
+ recursionLimit?: number;
13
+ autoWriteMemory?: boolean;
14
+ printSteps?: boolean;
15
+ fallbackText?: string;
16
+ commandWindowLabel?: string;
17
+ }
18
+ export declare function createDeepAgent<TConfig extends BaseAgentConfig>(ctx: BotContext<TConfig>, options?: DeepAgentOptions): Promise<{
19
+ agent: {
20
+ invoke: (input: {
21
+ messages: {
22
+ role: "user" | "assistant";
23
+ content: string;
24
+ }[];
25
+ }) => Promise<unknown>;
26
+ withConfig?: ((config: {
27
+ recursionLimit: number;
28
+ }) => {
29
+ invoke: (input: unknown) => Promise<unknown>;
30
+ }) | undefined;
31
+ };
32
+ run(userMessage: string): Promise<{
33
+ text: string;
34
+ messages?: unknown;
35
+ }>;
36
+ }>;
37
+ //# sourceMappingURL=deep-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deep-agent.d.ts","sourceRoot":"","sources":["../../src/agents/deep-agent.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAEtE,MAAM,WAAW,gBAAgB;IAC/B,KAAK,EAAE,OAAO,CAAC;IACf,GAAG,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC,CAAC;CAC7E;AAED,MAAM,WAAW,gBAAgB;IAC/B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAgHD,wBAAsB,eAAe,CAAC,OAAO,SAAS,eAAe,EAAE,GAAG,EAAE,UAAU,CAAC,OAAO,CAAC,EAAE,OAAO,GAAE,gBAAqB;;;;sBALjF,MAAM,GAAG,WAAW;yBAAW,MAAM;;cAAU,OAAO,CAAC,OAAO,CAAC;;4BACjE,MAAM;;4BAAyB,OAAO,KAAK,OAAO,CAAC,OAAO,CAAC;;;qBAiB5E,MAAM,GAAG,OAAO,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;GAmBhF"}