@easynet/agent-runtime 1.0.3 → 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.
- package/.github/workflows/ci.yml +9 -24
- package/.github/workflows/release.yml +14 -35
- package/agent-runtime/.github/workflows/ci.yml +69 -0
- package/agent-runtime/.github/workflows/release.yml +118 -0
- package/agent-runtime/.releaserc.cjs +26 -0
- package/agent-runtime/config/agent.deep.yaml +25 -0
- package/agent-runtime/config/agent.react.yaml +24 -0
- package/agent-runtime/example/basic-usage.ts +49 -0
- package/agent-runtime/package-lock.json +7740 -0
- package/agent-runtime/package.json +49 -0
- package/agent-runtime/pnpm-lock.yaml +3712 -0
- package/agent-runtime/scripts/resolve-deps.js +54 -0
- package/agent-runtime/src/agents/deep-agent.ts +165 -0
- package/agent-runtime/src/agents/react-agent.helpers.ts +227 -0
- package/agent-runtime/src/agents/react-agent.ts +584 -0
- package/{src → agent-runtime/src/agents}/sub-agent.ts +2 -2
- package/agent-runtime/src/cli/args.ts +15 -0
- package/agent-runtime/src/cli/event-listener.ts +162 -0
- package/agent-runtime/src/cli/interactive.ts +144 -0
- package/agent-runtime/src/cli/runtime.ts +31 -0
- package/agent-runtime/src/cli/spinner.ts +23 -0
- package/agent-runtime/src/cli/terminal-render.ts +322 -0
- package/agent-runtime/src/cli/types.ts +33 -0
- package/agent-runtime/src/cli.ts +134 -0
- package/agent-runtime/src/config/helpers.ts +179 -0
- package/agent-runtime/src/config/index.ts +245 -0
- package/agent-runtime/src/config/types.ts +62 -0
- package/agent-runtime/src/core/context.ts +266 -0
- package/agent-runtime/src/index.ts +55 -0
- package/agent-runtime/tsconfig.json +18 -0
- package/apps/imessagebot/README.md +38 -0
- package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/README.md +33 -0
- package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/package-lock.json +15257 -0
- package/apps/imessagebot/config/.agent/cache/easynet/agent-tool-buildin/0.0.45/package.json +55 -0
- package/apps/imessagebot/config/agents/deep/agent.yaml +31 -0
- package/apps/imessagebot/config/agents/react/agent.yaml +58 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/README.md +33 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/package-lock.json +15457 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.43/package.json +55 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/README.md +33 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/package-lock.json +15257 -0
- package/apps/imessagebot/config/agents/shared/.agent/cache/easynet/agent-tool-buildin/0.0.46/package.json +62 -0
- package/apps/imessagebot/config/agents/shared/memory.yaml +31 -0
- package/apps/imessagebot/config/agents/shared/model.yaml +23 -0
- package/apps/imessagebot/config/agents/shared/tool.yaml +13 -0
- package/apps/imessagebot/config/app.yaml +14 -0
- package/apps/imessagebot/package-lock.json +53695 -0
- package/apps/imessagebot/package.json +41 -0
- package/apps/imessagebot/pnpm-lock.yaml +1589 -0
- package/apps/imessagebot/scripts/resolve-deps.js +41 -0
- package/apps/imessagebot/scripts/test-llm.mjs +27 -0
- package/apps/imessagebot/scripts/validate-tools-config.mjs +174 -0
- package/apps/imessagebot/src/config.ts +76 -0
- package/apps/imessagebot/src/context.ts +35 -0
- package/apps/imessagebot/src/index.ts +17 -0
- package/apps/imessagebot/tsconfig.json +18 -0
- package/apps/itermbot/.github/workflows/ci.yml +61 -0
- package/apps/itermbot/.github/workflows/release.yml +80 -0
- package/apps/itermbot/.releaserc.cjs +26 -0
- package/apps/itermbot/README.md +82 -0
- package/apps/itermbot/config/app.yaml +29 -0
- package/apps/itermbot/config/tsconfig.json +18 -0
- package/apps/itermbot/macos_disk_usage_agent_plan.md +244 -0
- package/apps/itermbot/package-lock.json +53697 -0
- package/apps/itermbot/package.json +57 -0
- package/apps/itermbot/pnpm-lock.yaml +3966 -0
- package/apps/itermbot/scripts/patch-buildin-cache.sh +25 -0
- package/apps/itermbot/scripts/resolve-deps.js +41 -0
- package/apps/itermbot/scripts/test-llm.mjs +32 -0
- package/apps/itermbot/skills/command-explain-and-guard/SKILL.md +39 -0
- package/apps/itermbot/skills/command-explain-and-guard/handler.js +86 -0
- package/apps/itermbot/skills/disk-usage-investigate/SKILL.md +44 -0
- package/apps/itermbot/skills/disk-usage-investigate/handler.js +12 -0
- package/apps/itermbot/skills/gpu-ssh-monitor/SKILL.md +64 -0
- package/apps/itermbot/skills/repo-triage/SKILL.md +40 -0
- package/apps/itermbot/skills/repo-triage/handler.js +56 -0
- package/apps/itermbot/skills/test-failure-diagnose/SKILL.md +43 -0
- package/apps/itermbot/skills/test-failure-diagnose/handler.js +107 -0
- package/apps/itermbot/src/config.ts +95 -0
- package/apps/itermbot/src/context.ts +35 -0
- package/apps/itermbot/src/index.ts +223 -0
- package/apps/itermbot/src/iterm/session-hint.ts +40 -0
- package/apps/itermbot/src/iterm/target-routing.ts +419 -0
- package/apps/itermbot/src/startup/colors.ts +317 -0
- package/apps/itermbot/src/startup/diagnostics.ts +97 -0
- package/apps/itermbot/src/startup/ui.ts +141 -0
- package/config/agent.deep.yaml +25 -0
- package/config/agent.react.yaml +24 -0
- package/dist/agents/deep-agent.d.ts +37 -0
- package/dist/agents/deep-agent.d.ts.map +1 -0
- package/dist/agents/deep-agent.js +115 -0
- package/dist/agents/deep-agent.js.map +1 -0
- package/dist/agents/react-agent.d.ts +40 -0
- package/dist/agents/react-agent.d.ts.map +1 -0
- package/dist/agents/react-agent.helpers.d.ts +40 -0
- package/dist/agents/react-agent.helpers.d.ts.map +1 -0
- package/dist/agents/react-agent.helpers.js +196 -0
- package/dist/agents/react-agent.helpers.js.map +1 -0
- package/dist/agents/react-agent.js +400 -0
- package/dist/agents/react-agent.js.map +1 -0
- package/dist/agents/sub-agent.d.ts +34 -0
- package/dist/agents/sub-agent.d.ts.map +1 -0
- package/dist/agents/sub-agent.js +53 -0
- package/dist/agents/sub-agent.js.map +1 -0
- package/dist/cli/args.d.ts +8 -0
- package/dist/cli/args.d.ts.map +1 -0
- package/dist/cli/args.js +9 -0
- package/dist/cli/args.js.map +1 -0
- package/dist/cli/event-listener.d.ts +3 -0
- package/dist/cli/event-listener.d.ts.map +1 -0
- package/dist/cli/event-listener.js +131 -0
- package/dist/cli/event-listener.js.map +1 -0
- package/dist/cli/interactive.d.ts +4 -0
- package/dist/cli/interactive.d.ts.map +1 -0
- package/dist/cli/interactive.js +118 -0
- package/dist/cli/interactive.js.map +1 -0
- package/dist/cli/runtime.d.ts +8 -0
- package/dist/cli/runtime.d.ts.map +1 -0
- package/dist/cli/runtime.js +27 -0
- package/dist/cli/runtime.js.map +1 -0
- package/dist/cli/spinner.d.ts +2 -0
- package/dist/cli/spinner.d.ts.map +1 -0
- package/dist/cli/spinner.js +22 -0
- package/dist/cli/spinner.js.map +1 -0
- package/dist/cli/terminal-render.d.ts +7 -0
- package/dist/cli/terminal-render.d.ts.map +1 -0
- package/dist/cli/terminal-render.js +282 -0
- package/dist/cli/terminal-render.js.map +1 -0
- package/dist/cli/types.d.ts +29 -0
- package/dist/cli/types.d.ts.map +1 -0
- package/dist/cli/types.js +3 -0
- package/dist/cli/types.js.map +1 -0
- package/dist/cli.d.ts +4 -41
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +84 -588
- package/dist/cli.js.map +1 -1
- package/dist/config/helpers.d.ts +6 -0
- package/dist/config/helpers.d.ts.map +1 -0
- package/dist/config/helpers.js +164 -0
- package/dist/config/helpers.js.map +1 -0
- package/dist/config/index.d.ts +15 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +160 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +57 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/context.d.ts +8 -69
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +44 -24
- package/dist/context.js.map +1 -1
- package/dist/core/context.d.ts +66 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +149 -0
- package/dist/core/context.js.map +1 -0
- package/dist/deep-agent.d.ts +5 -2
- package/dist/deep-agent.d.ts.map +1 -1
- package/dist/deep-agent.js +44 -11
- package/dist/deep-agent.js.map +1 -1
- package/dist/index.d.ts +6 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -6
- package/dist/index.js.map +1 -1
- package/dist/middleware/malformed-tool-call-middleware.d.ts +8 -0
- package/dist/middleware/malformed-tool-call-middleware.d.ts.map +1 -0
- package/dist/middleware/malformed-tool-call-middleware.js +191 -0
- package/dist/middleware/malformed-tool-call-middleware.js.map +1 -0
- package/dist/react-agent.d.ts +2 -2
- package/dist/react-agent.d.ts.map +1 -1
- package/dist/react-agent.js +28 -9
- package/dist/react-agent.js.map +1 -1
- package/package.json +1 -1
- package/scripts/resolve-deps.js +54 -0
- package/src/agents/deep-agent.ts +165 -0
- package/src/agents/react-agent.helpers.ts +227 -0
- package/src/agents/react-agent.ts +584 -0
- package/src/agents/sub-agent.ts +82 -0
- package/src/cli/args.ts +15 -0
- package/src/cli/event-listener.ts +162 -0
- package/src/cli/interactive.ts +144 -0
- package/src/cli/runtime.ts +31 -0
- package/src/cli/spinner.ts +23 -0
- package/src/cli/terminal-render.ts +322 -0
- package/src/cli/types.ts +33 -0
- package/src/cli.ts +91 -702
- package/src/config/helpers.ts +179 -0
- package/src/config/index.ts +245 -0
- package/src/config/types.ts +62 -0
- package/src/core/context.ts +266 -0
- package/src/index.ts +13 -11
- package/src/middleware/malformed-tool-call-middleware.ts +239 -0
- package/src/types/markdown-it-terminal.d.ts +4 -0
- package/src/types/marked-terminal.d.ts +16 -0
- package/dist/config.d.ts +0 -86
- package/dist/config.d.ts.map +0 -1
- package/dist/config.js +0 -84
- package/dist/config.js.map +0 -1
- package/src/config.ts +0 -177
- package/src/context.ts +0 -247
- package/src/deep-agent.ts +0 -104
- package/src/react-agent.ts +0 -576
- /package/{src → agent-runtime/src/middleware}/malformed-tool-call-middleware.ts +0 -0
- /package/{src → agent-runtime/src/types}/markdown-it-terminal.d.ts +0 -0
- /package/{src → agent-runtime/src/types}/marked-terminal.d.ts +0 -0
package/dist/cli.js
CHANGED
|
@@ -2,613 +2,109 @@
|
|
|
2
2
|
* Shared CLI runner for agent apps.
|
|
3
3
|
* Provides: arg parsing, single-shot mode, interactive REPL, event logging.
|
|
4
4
|
*/
|
|
5
|
-
import
|
|
6
|
-
import {
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
function escapeRegExp(value) {
|
|
23
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
24
|
-
}
|
|
25
|
-
async function createRuntime(ctx, kind) {
|
|
26
|
-
if (kind === REACT) {
|
|
27
|
-
return createReactAgent(ctx, {
|
|
28
|
-
middleware: [malformedToolCallMiddleware()],
|
|
29
|
-
});
|
|
30
|
-
}
|
|
31
|
-
return createDeepAgent(ctx);
|
|
32
|
-
}
|
|
33
|
-
async function runOne(ctx, kind, query) {
|
|
34
|
-
const runtime = await createRuntime(ctx, kind);
|
|
35
|
-
const { text } = await runtime.run(query);
|
|
36
|
-
return text;
|
|
37
|
-
}
|
|
38
|
-
function createAnsi(useColor) {
|
|
39
|
-
return {
|
|
40
|
-
reset: useColor ? "\x1b[0m" : "",
|
|
41
|
-
dim: useColor ? "\x1b[2m" : "",
|
|
42
|
-
heading: useColor ? "\x1b[1;38;5;45m" : "",
|
|
43
|
-
bullet: useColor ? "\x1b[38;5;81m" : "",
|
|
44
|
-
code: useColor ? "\x1b[38;5;221m" : "",
|
|
45
|
-
quote: useColor ? "\x1b[38;5;245m" : "",
|
|
46
|
-
hr: useColor ? "\x1b[38;5;240m" : "",
|
|
47
|
-
};
|
|
48
|
-
}
|
|
49
|
-
function styleInlineMarkdown(line, ansi) {
|
|
50
|
-
return line
|
|
51
|
-
.replace(/`([^`]+)`/g, `${ansi.code}\`$1\`${ansi.reset}`)
|
|
52
|
-
.replace(/\*\*([^*]+)\*\*/g, `${ansi.heading}$1${ansi.reset}`);
|
|
53
|
-
}
|
|
54
|
-
function parseTableRow(line) {
|
|
55
|
-
const trimmed = line.trim().replace(/^\|/, "").replace(/\|$/, "");
|
|
56
|
-
return trimmed.split("|").map((cell) => cell.trim());
|
|
57
|
-
}
|
|
58
|
-
function isTableSeparatorRow(cells) {
|
|
59
|
-
return cells.length > 0 && cells.every((c) => /^:?-{3,}:?$/.test(c));
|
|
60
|
-
}
|
|
61
|
-
function renderTable(rows, ansi) {
|
|
62
|
-
const normalized = rows.map((r) => [...r]);
|
|
63
|
-
const colCount = Math.max(...normalized.map((r) => r.length));
|
|
64
|
-
for (const row of normalized) {
|
|
65
|
-
while (row.length < colCount)
|
|
66
|
-
row.push("");
|
|
67
|
-
}
|
|
68
|
-
const widths = Array.from({ length: colCount }, (_, i) => Math.max(...normalized.map((r) => (r[i] ?? "").length)));
|
|
69
|
-
const line = `+${widths.map((w) => "-".repeat(w + 2)).join("+")}+`;
|
|
70
|
-
const out = [`${ansi.hr}${line}${ansi.reset}`];
|
|
71
|
-
normalized.forEach((row, idx) => {
|
|
72
|
-
const body = row
|
|
73
|
-
.map((cell, i) => ` ${(cell ?? "").padEnd(widths[i] ?? 0)} `)
|
|
74
|
-
.join("|");
|
|
75
|
-
const styledBody = idx === 0
|
|
76
|
-
? `${ansi.heading}|${styleInlineMarkdown(body, ansi)}|${ansi.reset}`
|
|
77
|
-
: `|${styleInlineMarkdown(body, ansi)}|`;
|
|
78
|
-
out.push(styledBody);
|
|
79
|
-
if (idx === 0)
|
|
80
|
-
out.push(`${ansi.hr}${line}${ansi.reset}`);
|
|
81
|
-
});
|
|
82
|
-
out.push(`${ansi.hr}${line}${ansi.reset}`);
|
|
83
|
-
return out;
|
|
84
|
-
}
|
|
85
|
-
function formatMarkdownForTerminal(markdown, options = { useColor: true }) {
|
|
86
|
-
const ansi = createAnsi(options.useColor);
|
|
87
|
-
const lines = markdown.replace(/\r\n/g, "\n").split("\n");
|
|
88
|
-
const out = [];
|
|
89
|
-
let inCodeBlock = false;
|
|
90
|
-
let codeFenceLang = "";
|
|
91
|
-
let codeBoxWidth = 0;
|
|
92
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
93
|
-
const rawLine = lines[i];
|
|
94
|
-
const line = rawLine ?? "";
|
|
95
|
-
if (line.trim().startsWith("```")) {
|
|
96
|
-
if (!inCodeBlock) {
|
|
97
|
-
inCodeBlock = true;
|
|
98
|
-
codeFenceLang = line.trim().slice(3).trim();
|
|
99
|
-
const title = codeFenceLang ? ` code:${codeFenceLang} ` : " code ";
|
|
100
|
-
codeBoxWidth = Math.max(16, title.length + 4);
|
|
101
|
-
out.push(`${ansi.hr}┌${"─".repeat(codeBoxWidth)}┐${ansi.reset}`);
|
|
102
|
-
out.push(`${ansi.hr}│${ansi.reset}${ansi.dim}${title.padEnd(codeBoxWidth)}${ansi.reset}${ansi.hr}│${ansi.reset}`);
|
|
103
|
-
}
|
|
104
|
-
else {
|
|
105
|
-
inCodeBlock = false;
|
|
106
|
-
codeFenceLang = "";
|
|
107
|
-
out.push(`${ansi.hr}└${"─".repeat(codeBoxWidth)}┘${ansi.reset}`);
|
|
108
|
-
}
|
|
109
|
-
continue;
|
|
110
|
-
}
|
|
111
|
-
if (inCodeBlock) {
|
|
112
|
-
const content = line.length > codeBoxWidth ? line.slice(0, codeBoxWidth) : line.padEnd(codeBoxWidth);
|
|
113
|
-
out.push(`${ansi.hr}│${ansi.reset}${ansi.code}${content}${ansi.reset}${ansi.hr}│${ansi.reset}`);
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
// Markdown table: header row + separator row + data rows
|
|
117
|
-
if (line.includes("|") &&
|
|
118
|
-
i + 1 < lines.length &&
|
|
119
|
-
(lines[i + 1] ?? "").includes("|")) {
|
|
120
|
-
const header = parseTableRow(line);
|
|
121
|
-
const sep = parseTableRow(lines[i + 1] ?? "");
|
|
122
|
-
if (header.length > 1 && header.length === sep.length && isTableSeparatorRow(sep)) {
|
|
123
|
-
const rows = [header];
|
|
124
|
-
let j = i + 2;
|
|
125
|
-
while (j < lines.length && (lines[j] ?? "").includes("|")) {
|
|
126
|
-
rows.push(parseTableRow(lines[j] ?? ""));
|
|
127
|
-
j += 1;
|
|
128
|
-
}
|
|
129
|
-
out.push(...renderTable(rows, ansi));
|
|
130
|
-
i = j - 1;
|
|
131
|
-
continue;
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
if (/^\s*#{1,6}\s+/.test(line)) {
|
|
135
|
-
const headingText = line.replace(/^\s*#{1,6}\s+/, "").trim();
|
|
136
|
-
out.push(`${ansi.heading}${headingText}${ansi.reset}`);
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
if (/^\s*>\s?/.test(line)) {
|
|
140
|
-
out.push(`${ansi.quote}${line}${ansi.reset}`);
|
|
141
|
-
continue;
|
|
142
|
-
}
|
|
143
|
-
if (/^\s*([-*]|\d+\.)\s+/.test(line)) {
|
|
144
|
-
out.push(`${ansi.bullet}${styleInlineMarkdown(line, ansi)}${ansi.reset}`);
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (/^\s*---+\s*$/.test(line)) {
|
|
148
|
-
out.push(`${ansi.hr}${"─".repeat(56)}${ansi.reset}`);
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
out.push(styleInlineMarkdown(line, ansi));
|
|
152
|
-
}
|
|
153
|
-
return out.join("\n");
|
|
154
|
-
}
|
|
155
|
-
const markdownRenderers = new Map();
|
|
156
|
-
function getMarkdownRenderer(useColor) {
|
|
157
|
-
const key = useColor ? "color" : "plain";
|
|
158
|
-
const cached = markdownRenderers.get(key);
|
|
159
|
-
if (cached)
|
|
160
|
-
return cached;
|
|
161
|
-
const md = new MarkdownIt({
|
|
162
|
-
html: false,
|
|
163
|
-
linkify: true,
|
|
164
|
-
typographer: true,
|
|
165
|
-
breaks: false,
|
|
166
|
-
});
|
|
167
|
-
md.use(markdownItTerminal, {
|
|
168
|
-
indent: "",
|
|
169
|
-
...(useColor
|
|
170
|
-
? {}
|
|
171
|
-
: {
|
|
172
|
-
styleOptions: {
|
|
173
|
-
code: (s) => s,
|
|
174
|
-
blockquote: (s) => s,
|
|
175
|
-
html: (s) => s,
|
|
176
|
-
heading: (s) => s,
|
|
177
|
-
firstHeading: (s) => s,
|
|
178
|
-
hr: (s) => s,
|
|
179
|
-
listitem: (s) => s,
|
|
180
|
-
table: (s) => s,
|
|
181
|
-
paragraph: (s) => s,
|
|
182
|
-
strong: (s) => s,
|
|
183
|
-
em: (s) => s,
|
|
184
|
-
codespan: (s) => s,
|
|
185
|
-
del: (s) => s,
|
|
186
|
-
link: (s) => s,
|
|
187
|
-
href: (s) => s,
|
|
188
|
-
},
|
|
189
|
-
}),
|
|
190
|
-
});
|
|
191
|
-
markdownRenderers.set(key, md);
|
|
192
|
-
return md;
|
|
193
|
-
}
|
|
194
|
-
function normalizeAssistantMarkdown(text) {
|
|
195
|
-
const source = text.replace(/\r\n/g, "\n");
|
|
196
|
-
const hasMarkdownHeadings = /^\s*#{1,6}\s+/m.test(source);
|
|
197
|
-
const sanitizeLine = (line) => {
|
|
198
|
-
let next = line;
|
|
199
|
-
const trimmed = next.trim();
|
|
200
|
-
// Remove stray inline fence markers that frequently break markdown rendering.
|
|
201
|
-
if (next.includes("```") && !trimmed.startsWith("```")) {
|
|
202
|
-
next = next.replace(/```+/g, "").replace(/\s+$/, "");
|
|
5
|
+
import { createConsoleAgentEventListener } from "@easynet/agent-common";
|
|
6
|
+
import { parseArgs } from "./cli/args.js";
|
|
7
|
+
import { createStructuredRunEventListener } from "./cli/event-listener.js";
|
|
8
|
+
import { interactive } from "./cli/interactive.js";
|
|
9
|
+
import { readDefaultAgentKindFromConfig, runOne } from "./cli/runtime.js";
|
|
10
|
+
import { startLoadingSpinner } from "./cli/spinner.js";
|
|
11
|
+
import { renderForTerminal } from "./cli/terminal-render.js";
|
|
12
|
+
import { REACT } from "./cli/types.js";
|
|
13
|
+
export { createStructuredRunEventListener };
|
|
14
|
+
function createExitHandler(appName, onShutdown, ctx) {
|
|
15
|
+
let didCleanup = false;
|
|
16
|
+
const cleanup = () => {
|
|
17
|
+
if (didCleanup)
|
|
18
|
+
return;
|
|
19
|
+
didCleanup = true;
|
|
20
|
+
try {
|
|
21
|
+
onShutdown?.(ctx);
|
|
203
22
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
next = next.replace(/^\s*#{3,}\s+/, "## ");
|
|
23
|
+
catch (err) {
|
|
24
|
+
console.error(`${appName}: onShutdown hook failed:`, err instanceof Error ? err.message : err);
|
|
207
25
|
}
|
|
208
|
-
return next;
|
|
209
26
|
};
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
if (/^(\s{2,}|\t+)(\d+\.)\s+/.test(line)) {
|
|
215
|
-
return line.replace(/^(\s{2,}|\t+)(\d+\.)\s+/, "$2 ");
|
|
216
|
-
}
|
|
217
|
-
return line;
|
|
27
|
+
process.once("exit", cleanup);
|
|
28
|
+
const exitApp = (code) => {
|
|
29
|
+
cleanup();
|
|
30
|
+
process.exit(code);
|
|
218
31
|
};
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
if (bulletHeading?.[1]) {
|
|
227
|
-
return `### ${bulletHeading[1].trim()}`;
|
|
228
|
-
}
|
|
229
|
-
const plainBulletHeading = trimmed.match(/^[-*]\s+([^`].+):\s*$/);
|
|
230
|
-
if (plainBulletHeading?.[1] && plainBulletHeading[1].length <= 48) {
|
|
231
|
-
return `### ${plainBulletHeading[1].trim()}`;
|
|
232
|
-
}
|
|
233
|
-
if (hasMarkdownHeadings)
|
|
234
|
-
return trimmed === "Summary (3‑8 bullets)" ? "## Summary" : line;
|
|
235
|
-
const unwrapped = trimmed.replace(/^\*\*(.+)\*\*$/, "$1").trim();
|
|
236
|
-
if (/^(Key terminal output.*|Current terminal buffer.*|Summary.*|Next steps.*)$/i.test(unwrapped)) {
|
|
237
|
-
return `## ${unwrapped}`;
|
|
238
|
-
}
|
|
239
|
-
if (/^(Key observations|Findings|Analysis|Conclusion)$/i.test(unwrapped)) {
|
|
240
|
-
return `## ${unwrapped}`;
|
|
241
|
-
}
|
|
242
|
-
return line;
|
|
243
|
-
});
|
|
244
|
-
// Merge accidental line breaks inside list items so markdown renders as one bullet.
|
|
245
|
-
const merged = [];
|
|
246
|
-
for (let i = 0; i < titled.length; i += 1) {
|
|
247
|
-
const current = titled[i] ?? "";
|
|
248
|
-
const next = titled[i + 1] ?? "";
|
|
249
|
-
const currentTrim = current.trim();
|
|
250
|
-
const nextTrim = next.trim();
|
|
251
|
-
const isListLine = /^([-*]|\d+\.)\s+/.test(currentTrim);
|
|
252
|
-
const nextStartsNewBlock = nextTrim.length === 0 ||
|
|
253
|
-
/^([-*]|\d+\.)\s+/.test(nextTrim) ||
|
|
254
|
-
/^#{1,6}\s+/.test(nextTrim) ||
|
|
255
|
-
/^```/.test(nextTrim) ||
|
|
256
|
-
/^---+$/.test(nextTrim);
|
|
257
|
-
const looksLikeWrappedContinuation = isListLine &&
|
|
258
|
-
!nextStartsNewBlock &&
|
|
259
|
-
/^[0-9./~]/.test(nextTrim);
|
|
260
|
-
if (looksLikeWrappedContinuation) {
|
|
261
|
-
merged.push(`${current.replace(/\s+$/, "")} ${nextTrim}`);
|
|
262
|
-
i += 1;
|
|
263
|
-
continue;
|
|
264
|
-
}
|
|
265
|
-
merged.push(current);
|
|
266
|
-
}
|
|
267
|
-
const out = [];
|
|
268
|
-
for (let i = 0; i < merged.length; i += 1) {
|
|
269
|
-
const line = merged[i] ?? "";
|
|
270
|
-
out.push(line);
|
|
271
|
-
const heading = line.trim();
|
|
272
|
-
const isOutputHeading = /^##\s*(Key terminal output|Current terminal buffer|Terminal output)/i.test(heading);
|
|
273
|
-
if (!isOutputHeading)
|
|
274
|
-
continue;
|
|
275
|
-
if ((merged[i + 1] ?? "").trim().startsWith("```"))
|
|
276
|
-
continue;
|
|
277
|
-
let j = i + 1;
|
|
278
|
-
const block = [];
|
|
279
|
-
while (j < merged.length) {
|
|
280
|
-
const current = merged[j] ?? "";
|
|
281
|
-
if (!current.trim()) {
|
|
282
|
-
if (block.length === 0) {
|
|
283
|
-
j += 1;
|
|
284
|
-
continue;
|
|
285
|
-
}
|
|
286
|
-
break;
|
|
287
|
-
}
|
|
288
|
-
if (!/^\s{2,}\S/.test(current))
|
|
289
|
-
break;
|
|
290
|
-
block.push(current.replace(/^\s+/, ""));
|
|
291
|
-
j += 1;
|
|
292
|
-
}
|
|
293
|
-
if (block.length >= 2) {
|
|
294
|
-
out.push("```text");
|
|
295
|
-
out.push(...block);
|
|
296
|
-
out.push("```");
|
|
297
|
-
i = j - 1;
|
|
298
|
-
}
|
|
32
|
+
process.once("SIGINT", () => exitApp(130));
|
|
33
|
+
process.once("SIGTERM", () => exitApp(143));
|
|
34
|
+
return exitApp;
|
|
35
|
+
}
|
|
36
|
+
function subscribeEventListeners(options, ctx) {
|
|
37
|
+
if (process.env.AGENT_EVENT_STDERR === "1") {
|
|
38
|
+
ctx.events.subscribe(createConsoleAgentEventListener());
|
|
299
39
|
}
|
|
300
|
-
const
|
|
301
|
-
|
|
302
|
-
|
|
40
|
+
const listeners = Array.isArray(options.eventListener)
|
|
41
|
+
? options.eventListener
|
|
42
|
+
: options.eventListener
|
|
43
|
+
? [options.eventListener]
|
|
44
|
+
: [];
|
|
45
|
+
for (const listener of listeners) {
|
|
46
|
+
ctx.events.subscribe(listener);
|
|
303
47
|
}
|
|
304
|
-
return out.join("\n");
|
|
305
48
|
}
|
|
306
|
-
function
|
|
307
|
-
if (!options.
|
|
308
|
-
return
|
|
309
|
-
const normalizedText = normalizeAssistantMarkdown(text);
|
|
49
|
+
async function runOnReady(options, appName, ctx) {
|
|
50
|
+
if (!options.onReady)
|
|
51
|
+
return;
|
|
310
52
|
try {
|
|
311
|
-
|
|
53
|
+
await options.onReady(ctx);
|
|
312
54
|
}
|
|
313
|
-
catch {
|
|
314
|
-
|
|
55
|
+
catch (err) {
|
|
56
|
+
console.error(`${appName}: onReady hook failed:`, err instanceof Error ? err.message : err);
|
|
315
57
|
}
|
|
316
58
|
}
|
|
317
|
-
function
|
|
318
|
-
const
|
|
319
|
-
|
|
320
|
-
let
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
const base = trimmed.startsWith("⏳") ? trimmed : `⏳ ${trimmed}`;
|
|
325
|
-
const line = `${base}${frame}`;
|
|
326
|
-
const padded = lastLength > line.length ? line.padEnd(lastLength, " ") : line;
|
|
327
|
-
process.stderr.write(`\r${padded}\r`);
|
|
328
|
-
lastLength = padded.length;
|
|
329
|
-
frameIndex += 1;
|
|
330
|
-
};
|
|
331
|
-
render();
|
|
332
|
-
const timer = setInterval(render, 90);
|
|
333
|
-
return () => {
|
|
334
|
-
clearInterval(timer);
|
|
335
|
-
process.stderr.write(`\r${" ".repeat(lastLength)}\r`);
|
|
336
|
-
};
|
|
337
|
-
}
|
|
338
|
-
async function interactive(ctx, kind, options, exitApp) {
|
|
339
|
-
const name = kind === REACT ? "ReAct" : "Deep";
|
|
340
|
-
const runtime = await createRuntime(ctx, kind);
|
|
341
|
-
const userInfo = os.userInfo();
|
|
342
|
-
const userLabel = options.ui?.userLabel ?? `${userInfo.username}`;
|
|
343
|
-
const assistantLabel = options.ui?.assistantLabel ?? name;
|
|
344
|
-
const useColor = options.ui?.useColor ?? (Boolean(process.stdout.isTTY) && !process.env.NO_COLOR);
|
|
345
|
-
const renderMarkdown = options.ui?.renderMarkdown ?? true;
|
|
346
|
-
const echoUserQuestion = options.ui?.echoUserQuestion ?? true;
|
|
347
|
-
const showProcessingSpinner = options.ui?.processingSpinner ?? Boolean(process.stderr.isTTY);
|
|
348
|
-
const processingText = options.ui?.processingText ?? "Processing";
|
|
349
|
-
const color = {
|
|
350
|
-
reset: useColor ? "\x1b[0m" : "",
|
|
351
|
-
dim: useColor ? "\x1b[2m" : "",
|
|
352
|
-
user: useColor ? "\x1b[38;5;39m" : "",
|
|
353
|
-
bot: useColor ? "\x1b[38;5;48m" : "",
|
|
354
|
-
prompt: useColor ? "\x1b[38;5;245m" : "",
|
|
355
|
-
promptUser: useColor ? "\x1b[1;38;5;45m" : "",
|
|
356
|
-
};
|
|
357
|
-
const hr = `${color.dim}${"-".repeat(56)}${color.reset}`;
|
|
358
|
-
const promptText = `${color.prompt}[${color.promptUser}${userLabel}${color.reset}${color.prompt}]${color.reset} `;
|
|
359
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
360
|
-
const userLabelPrefixPattern = new RegExp(`^(?:\\[${escapeRegExp(userLabel)}\\]\\s*)+`, "i");
|
|
361
|
-
const prompt = () => rl.question(promptText, async (line) => {
|
|
362
|
-
const qRaw = line?.trim();
|
|
363
|
-
const q = qRaw?.replace(userLabelPrefixPattern, "").trim();
|
|
364
|
-
if (!q) {
|
|
365
|
-
prompt();
|
|
366
|
-
return;
|
|
367
|
-
}
|
|
368
|
-
if (q === "exit" || q === "quit") {
|
|
369
|
-
rl.close();
|
|
370
|
-
exitApp(0);
|
|
371
|
-
}
|
|
372
|
-
const handler = options.interactiveCommands?.[q.toLowerCase()];
|
|
373
|
-
if (handler) {
|
|
374
|
-
await handler(ctx);
|
|
375
|
-
prompt();
|
|
376
|
-
return;
|
|
377
|
-
}
|
|
378
|
-
let stopProcessingSpinner = null;
|
|
379
|
-
try {
|
|
380
|
-
console.log(`\n${hr}`);
|
|
381
|
-
if (echoUserQuestion) {
|
|
382
|
-
console.log(`${color.user}[${userLabel}]${color.reset}`);
|
|
383
|
-
console.log(`> ${q}`);
|
|
384
|
-
console.log("");
|
|
385
|
-
}
|
|
386
|
-
console.log(`${color.bot}[${assistantLabel}]${color.reset}`);
|
|
387
|
-
stopProcessingSpinner = showProcessingSpinner
|
|
388
|
-
? startLoadingSpinner(processingText === false ? "⏳" : `⏳ ${processingText}`)
|
|
389
|
-
: null;
|
|
390
|
-
const { text } = await runtime.run(q);
|
|
391
|
-
if (stopProcessingSpinner) {
|
|
392
|
-
stopProcessingSpinner();
|
|
393
|
-
stopProcessingSpinner = null;
|
|
394
|
-
}
|
|
395
|
-
console.log(renderForTerminal(text, { renderMarkdown, useColor }));
|
|
396
|
-
console.log(`${hr}\n`);
|
|
397
|
-
}
|
|
398
|
-
catch (err) {
|
|
399
|
-
if (stopProcessingSpinner) {
|
|
400
|
-
stopProcessingSpinner();
|
|
401
|
-
stopProcessingSpinner = null;
|
|
402
|
-
}
|
|
403
|
-
console.error("Error:", err instanceof Error ? err.message : err);
|
|
59
|
+
async function createContextWithLoading(options) {
|
|
60
|
+
const loadingText = options.ui?.loadingText ?? `${options.appName}: loading config, LLM, memory, tools...`;
|
|
61
|
+
const useLoadingSpinner = options.ui?.loadingSpinner ?? false;
|
|
62
|
+
let stopLoadingSpinner = null;
|
|
63
|
+
if (loadingText !== false) {
|
|
64
|
+
if (useLoadingSpinner && Boolean(process.stderr.isTTY)) {
|
|
65
|
+
stopLoadingSpinner = startLoadingSpinner(loadingText);
|
|
404
66
|
}
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
stopProcessingSpinner();
|
|
408
|
-
stopProcessingSpinner = null;
|
|
409
|
-
}
|
|
67
|
+
else {
|
|
68
|
+
console.error(loadingText);
|
|
410
69
|
}
|
|
411
|
-
prompt();
|
|
412
|
-
});
|
|
413
|
-
const introText = options.ui?.interactiveIntro ??
|
|
414
|
-
`${options.appName} (${name} agent). Type your message or "exit" to quit.`;
|
|
415
|
-
if (introText !== false) {
|
|
416
|
-
console.log(`${introText}\n`);
|
|
417
70
|
}
|
|
418
|
-
|
|
71
|
+
const ctx = await options.createBotContext();
|
|
72
|
+
stopLoadingSpinner?.();
|
|
73
|
+
return ctx;
|
|
74
|
+
}
|
|
75
|
+
function printReady(options, kind) {
|
|
76
|
+
const agentLabel = kind === REACT ? "ReAct (LangChain)" : "Deep (DeepAgents)";
|
|
77
|
+
const readyText = options.ui?.readyText ?? `Ready. Agent: ${agentLabel}`;
|
|
78
|
+
if (readyText !== false) {
|
|
79
|
+
console.error(readyText);
|
|
80
|
+
}
|
|
419
81
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
const
|
|
427
|
-
const
|
|
428
|
-
const
|
|
429
|
-
|
|
430
|
-
if (typeof value !== "string")
|
|
431
|
-
return null;
|
|
432
|
-
try {
|
|
433
|
-
const parsed = JSON.parse(value);
|
|
434
|
-
return asRecord(parsed);
|
|
435
|
-
}
|
|
436
|
-
catch {
|
|
437
|
-
return null;
|
|
438
|
-
}
|
|
439
|
-
};
|
|
440
|
-
const extractCommandMeta = (args) => {
|
|
441
|
-
const rec = asRecord(args) ?? parseJsonObject(args);
|
|
442
|
-
if (!rec)
|
|
443
|
-
return null;
|
|
444
|
-
const commandRaw = asAnyString(rec.command);
|
|
445
|
-
if (commandRaw === null)
|
|
446
|
-
return null;
|
|
447
|
-
const command = commandRaw.trim();
|
|
448
|
-
return {
|
|
449
|
-
command,
|
|
450
|
-
windowId: asNumber(rec.windowId),
|
|
451
|
-
tabIndex: asNumber(rec.tabIndex),
|
|
452
|
-
sessionId: asString(rec.sessionId),
|
|
453
|
-
};
|
|
454
|
-
};
|
|
455
|
-
const isNoopCaptureCommand = (command) => {
|
|
456
|
-
const normalized = command.trim().replace(/\s+/g, " ");
|
|
457
|
-
return (normalized === "" ||
|
|
458
|
-
normalized === ":" ||
|
|
459
|
-
normalized === "true" ||
|
|
460
|
-
normalized === "printf ''" ||
|
|
461
|
-
normalized === "printf \"\"");
|
|
462
|
-
};
|
|
463
|
-
const extractToolResultMeta = (payload) => {
|
|
464
|
-
const payloadRec = asRecord(payload);
|
|
465
|
-
const rawResult = payloadRec ? (payloadRec.result ?? null) : null;
|
|
466
|
-
const resultRec = asRecord(rawResult) ?? parseJsonObject(rawResult);
|
|
467
|
-
const nestedResult = resultRec ? asRecord(resultRec.result) : null;
|
|
468
|
-
const output = asString((nestedResult ?? resultRec ?? {}).output) ??
|
|
469
|
-
asString((nestedResult ?? resultRec ?? {}).result);
|
|
470
|
-
const outputLines = output ? output.split(/\r?\n/).filter((line) => line.length > 0).length : null;
|
|
471
|
-
const error = asString((nestedResult ?? resultRec ?? {}).error);
|
|
472
|
-
return { outputLines, error };
|
|
473
|
-
};
|
|
474
|
-
return (event) => {
|
|
475
|
-
switch (event.name) {
|
|
476
|
-
case "agent.react.run.start":
|
|
477
|
-
case "agent.deep.run.start":
|
|
478
|
-
step = 0;
|
|
479
|
-
lastCommandSignature = "";
|
|
480
|
-
stepActionByNumber.clear();
|
|
481
|
-
writer("Analyzing started");
|
|
482
|
-
return;
|
|
483
|
-
case "agent.react.skill.matched": {
|
|
484
|
-
const payload = (event.payload ?? {});
|
|
485
|
-
const score = typeof payload.score === "number" ? payload.score.toFixed(3) : "?";
|
|
486
|
-
writer(`[skill] matched ${payload.skill ?? "unknown"} (score ${score})`);
|
|
487
|
-
return;
|
|
488
|
-
}
|
|
489
|
-
case "agent.react.tool.invoke.start": {
|
|
490
|
-
step += 1;
|
|
491
|
-
const payload = (event.payload ?? {});
|
|
492
|
-
const commandMeta = extractCommandMeta(payload.args);
|
|
493
|
-
if (commandMeta) {
|
|
494
|
-
const signature = `${commandMeta.command}|${commandMeta.windowId ?? ""}|${commandMeta.tabIndex ?? ""}|${commandMeta.sessionId ?? ""}`;
|
|
495
|
-
const isRepeat = signature === lastCommandSignature;
|
|
496
|
-
lastCommandSignature = signature;
|
|
497
|
-
const action = isNoopCaptureCommand(commandMeta.command)
|
|
498
|
-
? "capture current screen"
|
|
499
|
-
: commandMeta.command;
|
|
500
|
-
stepActionByNumber.set(step, `${action}${isRepeat ? " (repeat)" : ""}`);
|
|
501
|
-
}
|
|
502
|
-
else {
|
|
503
|
-
stepActionByNumber.set(step, `tool: ${event.to}`);
|
|
504
|
-
}
|
|
505
|
-
return;
|
|
506
|
-
}
|
|
507
|
-
case "agent.react.tool.invoke.done": {
|
|
508
|
-
const resultMeta = extractToolResultMeta(event.payload);
|
|
509
|
-
const action = stepActionByNumber.get(step) ?? `tool: ${event.to}`;
|
|
510
|
-
if (resultMeta.error) {
|
|
511
|
-
writer(`[step ${step}] ${action} ✖ (${resultMeta.error})`);
|
|
512
|
-
stepActionByNumber.delete(step);
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
writer(`[step ${step}] ${action} ${okMark}`);
|
|
516
|
-
stepActionByNumber.delete(step);
|
|
517
|
-
return;
|
|
518
|
-
}
|
|
519
|
-
case "agent.react.tool.invoke.error": {
|
|
520
|
-
const payload = (event.payload ?? {});
|
|
521
|
-
const action = stepActionByNumber.get(step) ?? `tool: ${event.to}`;
|
|
522
|
-
const message = typeof payload.error === "string"
|
|
523
|
-
? payload.error
|
|
524
|
-
: payload.error instanceof Error
|
|
525
|
-
? payload.error.message
|
|
526
|
-
: "unknown error";
|
|
527
|
-
writer(`[step ${step}] ${action} ✖ (${message})`);
|
|
528
|
-
stepActionByNumber.delete(step);
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
case "agent.react.run.done":
|
|
532
|
-
case "agent.deep.run.done":
|
|
533
|
-
writer("completed");
|
|
534
|
-
return;
|
|
535
|
-
default:
|
|
536
|
-
return;
|
|
537
|
-
}
|
|
538
|
-
};
|
|
82
|
+
function resolveAgentKind(parsed, ctx) {
|
|
83
|
+
if (parsed.explicitKind)
|
|
84
|
+
return parsed.kind;
|
|
85
|
+
return readDefaultAgentKindFromConfig(ctx) ?? parsed.kind;
|
|
86
|
+
}
|
|
87
|
+
async function runSingleQuery(options, ctx, kind, query) {
|
|
88
|
+
const text = await runOne(ctx, kind, query);
|
|
89
|
+
const useColor = options.ui?.useColor ?? (Boolean(process.stdout.isTTY) && !process.env.NO_COLOR);
|
|
90
|
+
const renderMarkdown = options.ui?.renderMarkdown ?? true;
|
|
91
|
+
console.log(renderForTerminal(text, { renderMarkdown, useColor }));
|
|
539
92
|
}
|
|
540
93
|
export function runAppCli(options) {
|
|
541
|
-
const
|
|
542
|
-
|
|
543
|
-
const
|
|
544
|
-
const
|
|
545
|
-
const
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
else {
|
|
553
|
-
console.error(loadingText);
|
|
554
|
-
}
|
|
555
|
-
}
|
|
556
|
-
const ctx = await createBotContext();
|
|
557
|
-
if (stopLoadingSpinner) {
|
|
558
|
-
stopLoadingSpinner();
|
|
559
|
-
}
|
|
560
|
-
let didCleanup = false;
|
|
561
|
-
const cleanup = () => {
|
|
562
|
-
if (didCleanup)
|
|
563
|
-
return;
|
|
564
|
-
didCleanup = true;
|
|
565
|
-
try {
|
|
566
|
-
options.onShutdown?.(ctx);
|
|
567
|
-
}
|
|
568
|
-
catch (err) {
|
|
569
|
-
console.error(`${appName}: onShutdown hook failed:`, err instanceof Error ? err.message : err);
|
|
570
|
-
}
|
|
571
|
-
};
|
|
572
|
-
const exitApp = (code) => {
|
|
573
|
-
cleanup();
|
|
574
|
-
process.exit(code);
|
|
575
|
-
};
|
|
576
|
-
process.once("exit", cleanup);
|
|
577
|
-
process.once("SIGINT", () => exitApp(130));
|
|
578
|
-
process.once("SIGTERM", () => exitApp(143));
|
|
579
|
-
if (process.env.AGENT_EVENT_STDERR === "1") {
|
|
580
|
-
ctx.events.subscribe(createConsoleAgentEventListener());
|
|
581
|
-
}
|
|
582
|
-
const eventListeners = Array.isArray(options.eventListener)
|
|
583
|
-
? options.eventListener
|
|
584
|
-
: options.eventListener
|
|
585
|
-
? [options.eventListener]
|
|
586
|
-
: [];
|
|
587
|
-
for (const listener of eventListeners) {
|
|
588
|
-
ctx.events.subscribe(listener);
|
|
589
|
-
}
|
|
590
|
-
if (options.onReady) {
|
|
591
|
-
try {
|
|
592
|
-
await options.onReady(ctx);
|
|
593
|
-
}
|
|
594
|
-
catch (err) {
|
|
595
|
-
console.error(`${appName}: onReady hook failed:`, err instanceof Error ? err.message : err);
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
const readyText = options.ui?.readyText ?? `Ready. Agent: ${agentLabel}`;
|
|
599
|
-
if (readyText !== false) {
|
|
600
|
-
console.error(readyText);
|
|
601
|
-
}
|
|
602
|
-
if (query) {
|
|
603
|
-
const text = await runOne(ctx, kind, query);
|
|
604
|
-
const useColor = options.ui?.useColor ?? (Boolean(process.stdout.isTTY) && !process.env.NO_COLOR);
|
|
605
|
-
const renderMarkdown = options.ui?.renderMarkdown ?? true;
|
|
606
|
-
console.log(renderForTerminal(text, { renderMarkdown, useColor }));
|
|
607
|
-
cleanup();
|
|
608
|
-
return;
|
|
94
|
+
const main = async () => {
|
|
95
|
+
const parsed = parseArgs();
|
|
96
|
+
const ctx = await createContextWithLoading(options);
|
|
97
|
+
const kind = resolveAgentKind(parsed, ctx);
|
|
98
|
+
const exitApp = createExitHandler(options.appName, options.onShutdown, ctx);
|
|
99
|
+
subscribeEventListeners(options, ctx);
|
|
100
|
+
await runOnReady(options, options.appName, ctx);
|
|
101
|
+
printReady(options, kind);
|
|
102
|
+
if (parsed.query) {
|
|
103
|
+
await runSingleQuery(options, ctx, kind, parsed.query);
|
|
104
|
+
exitApp(0);
|
|
609
105
|
}
|
|
610
106
|
await interactive(ctx, kind, options, exitApp);
|
|
611
|
-
}
|
|
107
|
+
};
|
|
612
108
|
main().catch((err) => {
|
|
613
109
|
console.error(err);
|
|
614
110
|
process.exit(1);
|