@moxxy/cli 0.0.12 → 0.1.0
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/README.md +278 -112
- package/bin/moxxy +10 -0
- package/package.json +36 -53
- package/src/api-client.js +286 -0
- package/src/cli.js +341 -0
- package/src/commands/agent.js +413 -0
- package/src/commands/auth.js +326 -0
- package/src/commands/channel.js +285 -0
- package/src/commands/doctor.js +261 -0
- package/src/commands/events.js +80 -0
- package/src/commands/gateway.js +428 -0
- package/src/commands/heartbeat.js +145 -0
- package/src/commands/init.js +767 -0
- package/src/commands/mcp.js +278 -0
- package/src/commands/plugin.js +583 -0
- package/src/commands/provider.js +1934 -0
- package/src/commands/skill.js +125 -0
- package/src/commands/template.js +237 -0
- package/src/commands/uninstall.js +196 -0
- package/src/commands/update.js +406 -0
- package/src/commands/vault.js +219 -0
- package/src/help.js +368 -0
- package/src/lib/plugin-registry.js +98 -0
- package/src/platform.js +40 -0
- package/src/sse-client.js +79 -0
- package/src/tui/action-wizards.js +130 -0
- package/src/tui/app.jsx +859 -0
- package/src/tui/components/action-picker.jsx +86 -0
- package/src/tui/components/chat-panel.jsx +120 -0
- package/src/tui/components/footer.jsx +13 -0
- package/src/tui/components/header.jsx +45 -0
- package/src/tui/components/input-area.jsx +384 -0
- package/src/tui/components/messages/ask-message.jsx +13 -0
- package/src/tui/components/messages/assistant-message.jsx +165 -0
- package/src/tui/components/messages/channel-message.jsx +18 -0
- package/src/tui/components/messages/event-message.jsx +22 -0
- package/src/tui/components/messages/hive-status.jsx +34 -0
- package/src/tui/components/messages/skill-message.jsx +31 -0
- package/src/tui/components/messages/system-message.jsx +12 -0
- package/src/tui/components/messages/thinking.jsx +25 -0
- package/src/tui/components/messages/tool-group.jsx +62 -0
- package/src/tui/components/messages/tool-message.jsx +66 -0
- package/src/tui/components/messages/user-message.jsx +12 -0
- package/src/tui/components/model-picker.jsx +138 -0
- package/src/tui/components/multiline-input.jsx +72 -0
- package/src/tui/events-handler.js +730 -0
- package/src/tui/helpers.js +59 -0
- package/src/tui/hooks/use-command-handler.js +451 -0
- package/src/tui/index.jsx +55 -0
- package/src/tui/input-utils.js +26 -0
- package/src/tui/markdown-renderer.js +66 -0
- package/src/tui/mcp-wizard.js +136 -0
- package/src/tui/model-picker.js +174 -0
- package/src/tui/slash-commands.js +26 -0
- package/src/tui/store.js +12 -0
- package/src/tui/theme.js +17 -0
- package/src/ui.js +109 -0
- package/bin/moxxy.js +0 -2
- package/dist/chunk-23LZYKQ6.mjs +0 -1131
- package/dist/chunk-2FZEA3NG.mjs +0 -457
- package/dist/chunk-3KDPLS22.mjs +0 -1131
- package/dist/chunk-3QRJTRBT.mjs +0 -1102
- package/dist/chunk-6DZX6EAA.mjs +0 -37
- package/dist/chunk-A4WRDUNY.mjs +0 -1242
- package/dist/chunk-C46NSEKG.mjs +0 -211
- package/dist/chunk-CAUXONEF.mjs +0 -1131
- package/dist/chunk-CPL5V56X.mjs +0 -1131
- package/dist/chunk-CTBVTTBG.mjs +0 -440
- package/dist/chunk-FHHLXTEZ.mjs +0 -1121
- package/dist/chunk-FXY3GPVA.mjs +0 -1126
- package/dist/chunk-GSNMMI3H.mjs +0 -530
- package/dist/chunk-HHOAOGUS.mjs +0 -1242
- package/dist/chunk-ITBO7BKI.mjs +0 -1243
- package/dist/chunk-J33O35WX.mjs +0 -532
- package/dist/chunk-N5JTPB6U.mjs +0 -820
- package/dist/chunk-NGVL4Q5C.mjs +0 -1102
- package/dist/chunk-Q2OCMNYI.mjs +0 -1131
- package/dist/chunk-QDVRLN6D.mjs +0 -1121
- package/dist/chunk-QO2JONHP.mjs +0 -1131
- package/dist/chunk-RVAPILHA.mjs +0 -1242
- package/dist/chunk-S7YBOV7E.mjs +0 -1131
- package/dist/chunk-SHIG6Y5L.mjs +0 -1074
- package/dist/chunk-SOFST2PV.mjs +0 -1242
- package/dist/chunk-SUNUYS6G.mjs +0 -1243
- package/dist/chunk-TMZWETMH.mjs +0 -1242
- package/dist/chunk-TYD7NMMI.mjs +0 -581
- package/dist/chunk-TYQ3YS42.mjs +0 -1068
- package/dist/chunk-UALWCJ7F.mjs +0 -1131
- package/dist/chunk-UQZKODNW.mjs +0 -1124
- package/dist/chunk-USC6R2ON.mjs +0 -1242
- package/dist/chunk-W32EQCVC.mjs +0 -823
- package/dist/chunk-WMB5ENMC.mjs +0 -1242
- package/dist/chunk-WNHA5JAP.mjs +0 -1242
- package/dist/cli-2AIWTL6F.mjs +0 -8
- package/dist/cli-2QKJ5UUL.mjs +0 -8
- package/dist/cli-4RIS6DQX.mjs +0 -8
- package/dist/cli-5RH4VBBL.mjs +0 -7
- package/dist/cli-7MK4YGOP.mjs +0 -7
- package/dist/cli-B4KH6MZI.mjs +0 -8
- package/dist/cli-CGO2LZ6Z.mjs +0 -8
- package/dist/cli-CVP26EL2.mjs +0 -8
- package/dist/cli-DDRVVNAV.mjs +0 -8
- package/dist/cli-E7U56QVQ.mjs +0 -8
- package/dist/cli-EQNRMLL3.mjs +0 -8
- package/dist/cli-F5RUHHH4.mjs +0 -8
- package/dist/cli-LX6FFSEF.mjs +0 -8
- package/dist/cli-LY74GWKR.mjs +0 -6
- package/dist/cli-MAT3ZJHI.mjs +0 -8
- package/dist/cli-NJXXTQYF.mjs +0 -8
- package/dist/cli-O4ZGFAZG.mjs +0 -8
- package/dist/cli-ORVLI3UQ.mjs +0 -8
- package/dist/cli-PV43ZVKA.mjs +0 -8
- package/dist/cli-REVD6ISM.mjs +0 -8
- package/dist/cli-TBX76KQX.mjs +0 -8
- package/dist/cli-THCGF7SQ.mjs +0 -8
- package/dist/cli-TLX5ENVM.mjs +0 -8
- package/dist/cli-TMNI5ZYE.mjs +0 -8
- package/dist/cli-TNJHCBQA.mjs +0 -6
- package/dist/cli-TUX22CZP.mjs +0 -8
- package/dist/cli-XJVH7EEP.mjs +0 -8
- package/dist/cli-XXOW4VXJ.mjs +0 -8
- package/dist/cli-XZ5RESNB.mjs +0 -6
- package/dist/cli-YCBYZ76Q.mjs +0 -8
- package/dist/cli-ZLMQCU7X.mjs +0 -8
- package/dist/dist-2VGKJRBH.mjs +0 -6820
- package/dist/dist-37BNX4QG.mjs +0 -7081
- package/dist/dist-7LTHRYKA.mjs +0 -11569
- package/dist/dist-7XJPQW5C.mjs +0 -6950
- package/dist/dist-AYMVOW7T.mjs +0 -7123
- package/dist/dist-BHUWCDRS.mjs +0 -7132
- package/dist/dist-FAXRJMEN.mjs +0 -6812
- package/dist/dist-HQGANM3P.mjs +0 -6976
- package/dist/dist-KATLOZQV.mjs +0 -7054
- package/dist/dist-KLSB6YHV.mjs +0 -6964
- package/dist/dist-LKIOZQ42.mjs +0 -17
- package/dist/dist-UYA4RJUH.mjs +0 -2792
- package/dist/dist-ZYHCBILM.mjs +0 -6993
- package/dist/index.d.mts +0 -23
- package/dist/index.d.ts +0 -23
- package/dist/index.js +0 -25531
- package/dist/index.mjs +0 -18
- package/dist/src-APP5P3UD.mjs +0 -1386
- package/dist/src-D5HMDDVE.mjs +0 -1324
- package/dist/src-EK3WD4AU.mjs +0 -1327
- package/dist/src-LSZFLMFN.mjs +0 -1400
- package/dist/src-T77DFTFP.mjs +0 -1407
- package/dist/src-WIOCZRAC.mjs +0 -1397
- package/dist/src-YK6CHCMW.mjs +0 -1400
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Doctor command: diagnose the Moxxy installation.
|
|
3
|
+
* Checks gateway, auth, providers, agents, storage, and environment.
|
|
4
|
+
*/
|
|
5
|
+
import { p, withSpinner } from '../ui.js';
|
|
6
|
+
import { getMoxxyHome } from './init.js';
|
|
7
|
+
import { existsSync, statSync, readdirSync } from 'node:fs';
|
|
8
|
+
import { join } from 'node:path';
|
|
9
|
+
import { execSync } from 'node:child_process';
|
|
10
|
+
import { platform } from 'node:os';
|
|
11
|
+
|
|
12
|
+
export async function runDoctor(client, args) {
|
|
13
|
+
p.intro('Moxxy Doctor');
|
|
14
|
+
|
|
15
|
+
let pass = 0;
|
|
16
|
+
let warn = 0;
|
|
17
|
+
let fail = 0;
|
|
18
|
+
|
|
19
|
+
function ok(msg) { p.log.success(msg); pass++; }
|
|
20
|
+
function warning(msg) { p.log.warn(msg); warn++; }
|
|
21
|
+
function error(msg) { p.log.error(msg); fail++; }
|
|
22
|
+
|
|
23
|
+
// ── 1. Moxxy Home Directory ──
|
|
24
|
+
|
|
25
|
+
const moxxyHome = getMoxxyHome();
|
|
26
|
+
if (existsSync(moxxyHome)) {
|
|
27
|
+
ok(`Moxxy home exists: ${moxxyHome}`);
|
|
28
|
+
|
|
29
|
+
if (existsSync(join(moxxyHome, 'agents'))) {
|
|
30
|
+
const agents = readdirSync(join(moxxyHome, 'agents'));
|
|
31
|
+
ok(`Agents directory: ${agents.length} agent(s)`);
|
|
32
|
+
} else {
|
|
33
|
+
warning('Agents directory missing. Run: moxxy init');
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
if (existsSync(join(moxxyHome, 'config'))) {
|
|
37
|
+
ok('Config directory exists');
|
|
38
|
+
} else {
|
|
39
|
+
warning('Config directory missing. Run: moxxy init');
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const dbPath = join(moxxyHome, 'moxxy.db');
|
|
43
|
+
if (existsSync(dbPath)) {
|
|
44
|
+
const size = statSync(dbPath).size;
|
|
45
|
+
ok(`Database: ${dbPath} (${formatBytes(size)})`);
|
|
46
|
+
} else {
|
|
47
|
+
warning('Database not found. Start the gateway to create it.');
|
|
48
|
+
}
|
|
49
|
+
} else {
|
|
50
|
+
error(`Moxxy home not found: ${moxxyHome}`);
|
|
51
|
+
p.log.info(' Run: moxxy init');
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// ── 2. Environment Variables ──
|
|
55
|
+
|
|
56
|
+
const apiUrl = process.env.MOXXY_API_URL || 'http://localhost:3000';
|
|
57
|
+
ok(`API URL: ${apiUrl}`);
|
|
58
|
+
|
|
59
|
+
if (process.env.MOXXY_TOKEN) {
|
|
60
|
+
const token = process.env.MOXXY_TOKEN;
|
|
61
|
+
const masked = token.slice(0, 8) + '...' + token.slice(-4);
|
|
62
|
+
ok(`API token set: ${masked}`);
|
|
63
|
+
} else {
|
|
64
|
+
warning('MOXXY_TOKEN not set. Some commands will fail.');
|
|
65
|
+
p.log.info(' Run: moxxy init or moxxy auth token create');
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// ── 3. Gateway Connectivity ──
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
const resp = await fetch(`${apiUrl}/v1/providers`);
|
|
72
|
+
if (resp) {
|
|
73
|
+
ok(`Gateway reachable at ${apiUrl} (HTTP ${resp.status})`);
|
|
74
|
+
}
|
|
75
|
+
} catch {
|
|
76
|
+
error(`Gateway not reachable at ${apiUrl}`);
|
|
77
|
+
p.log.info(' Run: moxxy gateway start or cargo run -p moxxy-gateway');
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// ── 4. Auth Check ──
|
|
81
|
+
|
|
82
|
+
if (process.env.MOXXY_TOKEN) {
|
|
83
|
+
try {
|
|
84
|
+
await client.listTokens();
|
|
85
|
+
ok('Authentication working');
|
|
86
|
+
} catch (err) {
|
|
87
|
+
if (err.status === 401) {
|
|
88
|
+
error('Token is invalid or expired');
|
|
89
|
+
p.log.info(' Run: moxxy auth token create');
|
|
90
|
+
} else if (err.status === 403) {
|
|
91
|
+
warning('Token lacks tokens:admin scope (auth check limited)');
|
|
92
|
+
} else {
|
|
93
|
+
warning(`Auth check inconclusive: ${err.message}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ── 5. Providers ──
|
|
99
|
+
|
|
100
|
+
try {
|
|
101
|
+
const providers = await client.listProviders();
|
|
102
|
+
if (Array.isArray(providers) && providers.length > 0) {
|
|
103
|
+
ok(`Providers installed: ${providers.map(pr => pr.display_name || pr.id).join(', ')}`);
|
|
104
|
+
} else {
|
|
105
|
+
warning('No providers installed. Run: moxxy provider install');
|
|
106
|
+
}
|
|
107
|
+
} catch {
|
|
108
|
+
// Skip if gateway/auth not available
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// ── 6. Agents ──
|
|
112
|
+
|
|
113
|
+
try {
|
|
114
|
+
const agents = await client.listAgents();
|
|
115
|
+
if (Array.isArray(agents) && agents.length > 0) {
|
|
116
|
+
const running = agents.filter(a => a.status === 'running').length;
|
|
117
|
+
ok(`Agents: ${agents.length} total, ${running} running`);
|
|
118
|
+
} else {
|
|
119
|
+
warning('No agents created. Run: moxxy agent create');
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
// Skip if gateway/auth not available
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// ── 7. Rust Toolchain ──
|
|
126
|
+
|
|
127
|
+
try {
|
|
128
|
+
const rustVersion = execSync('rustc --version', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
129
|
+
ok(`Rust: ${rustVersion}`);
|
|
130
|
+
} catch {
|
|
131
|
+
warning('Rust not found. Required to build/run the gateway.');
|
|
132
|
+
p.log.info(' Install: https://rustup.rs');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// ── 8. Node.js Runtime ──
|
|
136
|
+
|
|
137
|
+
try {
|
|
138
|
+
const nodeVersion = execSync('node --version', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
139
|
+
const parts = nodeVersion.replace(/^v/, '').split('.').map(Number);
|
|
140
|
+
const nodeOk = parts[0] >= 18;
|
|
141
|
+
if (nodeOk) {
|
|
142
|
+
ok(`Node.js: ${nodeVersion}`);
|
|
143
|
+
} else {
|
|
144
|
+
error(`Node.js ${nodeVersion} is too old. Requires >= 18.0.0`);
|
|
145
|
+
p.log.info(' Update: https://nodejs.org');
|
|
146
|
+
}
|
|
147
|
+
} catch {
|
|
148
|
+
error('Node.js not found. Required to run the CLI.');
|
|
149
|
+
p.log.info(' Install: https://nodejs.org');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ── 9. Git ──
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const gitVersion = execSync('git --version', { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
156
|
+
ok(`Git: ${gitVersion}`);
|
|
157
|
+
} catch {
|
|
158
|
+
warning('Git not found. Required for git.* primitives.');
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
// ── 10. Chrome/Chromium ──
|
|
162
|
+
|
|
163
|
+
const chromePaths = [
|
|
164
|
+
process.env.CHROME_PATH,
|
|
165
|
+
'/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
|
|
166
|
+
'/usr/bin/google-chrome',
|
|
167
|
+
'/usr/bin/google-chrome-stable',
|
|
168
|
+
'/usr/bin/chromium',
|
|
169
|
+
'/usr/bin/chromium-browser',
|
|
170
|
+
...(platform() === 'win32' ? [
|
|
171
|
+
join(process.env.PROGRAMFILES || '', 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
172
|
+
join(process.env.LOCALAPPDATA || '', 'Google', 'Chrome', 'Application', 'chrome.exe'),
|
|
173
|
+
join(process.env.PROGRAMFILES || '', 'Chromium', 'Application', 'chrome.exe'),
|
|
174
|
+
] : []),
|
|
175
|
+
].filter(Boolean);
|
|
176
|
+
|
|
177
|
+
let chromeFound = false;
|
|
178
|
+
for (const chromePath of chromePaths) {
|
|
179
|
+
if (existsSync(chromePath)) {
|
|
180
|
+
ok(`Chrome/Chromium: ${chromePath}`);
|
|
181
|
+
chromeFound = true;
|
|
182
|
+
break;
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (!chromeFound) {
|
|
186
|
+
try {
|
|
187
|
+
const cmd = platform() === 'win32'
|
|
188
|
+
? 'where google-chrome chromium 2>nul'
|
|
189
|
+
: 'which google-chrome chromium';
|
|
190
|
+
const found = execSync(cmd, { encoding: 'utf-8', stdio: 'pipe' }).trim();
|
|
191
|
+
if (found) {
|
|
192
|
+
ok(`Chrome/Chromium: ${found.split('\n')[0]}`);
|
|
193
|
+
chromeFound = true;
|
|
194
|
+
}
|
|
195
|
+
} catch { /* ignore */ }
|
|
196
|
+
}
|
|
197
|
+
if (!chromeFound) {
|
|
198
|
+
warning('Chrome/Chromium not found. Optional for browse.* primitives with JS rendering.');
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// ── 11. API Key Environment Variables ──
|
|
202
|
+
|
|
203
|
+
const apiKeys = [
|
|
204
|
+
{ env: 'ANTHROPIC_API_KEY', name: 'Anthropic' },
|
|
205
|
+
{ env: 'OPENAI_API_KEY', name: 'OpenAI' },
|
|
206
|
+
{ env: 'XAI_API_KEY', name: 'xAI' },
|
|
207
|
+
{ env: 'GOOGLE_API_KEY', name: 'Google' },
|
|
208
|
+
{ env: 'DEEPSEEK_API_KEY', name: 'DeepSeek' },
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
const setKeys = apiKeys.filter(k => process.env[k.env]);
|
|
212
|
+
if (setKeys.length > 0) {
|
|
213
|
+
ok(`API keys found: ${setKeys.map(k => k.name).join(', ')}`);
|
|
214
|
+
} else {
|
|
215
|
+
warning('No provider API keys set in environment');
|
|
216
|
+
p.log.info(' Set one of: ANTHROPIC_API_KEY, OPENAI_API_KEY, XAI_API_KEY, ...');
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
// ── 12. Plugins ──
|
|
220
|
+
|
|
221
|
+
try {
|
|
222
|
+
const { pluginPaths, readRegistry, isProcessAlive } = await import('../lib/plugin-registry.js');
|
|
223
|
+
const { registryFile } = pluginPaths();
|
|
224
|
+
if (existsSync(registryFile)) {
|
|
225
|
+
const registry = readRegistry();
|
|
226
|
+
const plugins = Object.values(registry.plugins);
|
|
227
|
+
const running = plugins.filter(pl => pl.status === 'running' && pl.pid && isProcessAlive(pl.pid));
|
|
228
|
+
ok(`Plugins: ${plugins.length} installed, ${running.length} running`);
|
|
229
|
+
for (const plug of running) {
|
|
230
|
+
ok(` ${plug.name} v${plug.version} (PID ${plug.pid})`);
|
|
231
|
+
}
|
|
232
|
+
const zombies = plugins.filter(pl => pl.status === 'running' && pl.pid && !isProcessAlive(pl.pid));
|
|
233
|
+
for (const z of zombies) {
|
|
234
|
+
warning(` ${z.name} marked running but PID ${z.pid} is dead`);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
} catch { /* plugins not set up yet */ }
|
|
238
|
+
|
|
239
|
+
// ── Summary ──
|
|
240
|
+
|
|
241
|
+
const total = pass + warn + fail;
|
|
242
|
+
p.note(
|
|
243
|
+
`${pass}/${total} checks passed\n${warn} warning(s)\n${fail} error(s)`,
|
|
244
|
+
fail === 0 ? 'All good' : 'Issues found',
|
|
245
|
+
);
|
|
246
|
+
|
|
247
|
+
if (fail === 0 && warn === 0) {
|
|
248
|
+
p.outro('Moxxy is healthy!');
|
|
249
|
+
} else if (fail === 0) {
|
|
250
|
+
p.outro('Moxxy is working but has some warnings.');
|
|
251
|
+
} else {
|
|
252
|
+
p.outro('Fix the errors above to get Moxxy working.');
|
|
253
|
+
process.exitCode = 1;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
function formatBytes(bytes) {
|
|
258
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
259
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
260
|
+
return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
261
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Events command: tail SSE stream.
|
|
3
|
+
*/
|
|
4
|
+
import { createSseClient } from '../sse-client.js';
|
|
5
|
+
import { parseFlags } from './auth.js';
|
|
6
|
+
import { isInteractive, handleCancel, pickAgent, p } from '../ui.js';
|
|
7
|
+
|
|
8
|
+
export async function runEvents(client, args) {
|
|
9
|
+
let [action, ...rest] = args;
|
|
10
|
+
|
|
11
|
+
// Default to 'tail' in interactive mode when no action
|
|
12
|
+
if (!action && isInteractive()) {
|
|
13
|
+
action = 'tail';
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
if (action !== 'tail') {
|
|
17
|
+
const { showHelp } = await import('../help.js');
|
|
18
|
+
showHelp('events', p);
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const flags = parseFlags(rest);
|
|
23
|
+
const filters = {};
|
|
24
|
+
|
|
25
|
+
// Interactive filter wizard when no filters provided
|
|
26
|
+
if (!flags.agent && !flags.run && isInteractive()) {
|
|
27
|
+
const filterMode = await p.select({
|
|
28
|
+
message: 'Event filter',
|
|
29
|
+
options: [
|
|
30
|
+
{ value: 'all', label: 'All events', hint: 'stream all events' },
|
|
31
|
+
{ value: 'agent', label: 'By agent', hint: 'filter by specific agent' },
|
|
32
|
+
],
|
|
33
|
+
});
|
|
34
|
+
handleCancel(filterMode);
|
|
35
|
+
|
|
36
|
+
if (filterMode === 'agent') {
|
|
37
|
+
const agentId = await pickAgent(client, 'Select agent to tail');
|
|
38
|
+
filters.agent_id = agentId;
|
|
39
|
+
}
|
|
40
|
+
} else {
|
|
41
|
+
if (flags.agent) filters.agent_id = flags.agent;
|
|
42
|
+
if (flags.run) filters.run_id = flags.run;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const sse = createSseClient(client.baseUrl, client.token, filters);
|
|
46
|
+
|
|
47
|
+
if (isInteractive()) {
|
|
48
|
+
p.log.info(`Connecting to ${sse.url} ...`);
|
|
49
|
+
} else {
|
|
50
|
+
console.error(`Connecting to ${sse.url} ...`);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
process.on('SIGINT', () => {
|
|
54
|
+
sse.disconnect();
|
|
55
|
+
if (isInteractive()) {
|
|
56
|
+
p.log.info('Disconnected.');
|
|
57
|
+
} else {
|
|
58
|
+
console.error('\nDisconnected.');
|
|
59
|
+
}
|
|
60
|
+
process.exit(0);
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
try {
|
|
64
|
+
for await (const event of sse.stream()) {
|
|
65
|
+
if (flags.json === true || flags.json === 'true') {
|
|
66
|
+
console.log(JSON.stringify(event));
|
|
67
|
+
} else {
|
|
68
|
+
const ts = event.ts ? new Date(event.ts).toISOString() : '?';
|
|
69
|
+
const type = event.event_type || 'unknown';
|
|
70
|
+
const agent = event.agent_id || '-';
|
|
71
|
+
console.log(`[${ts}] ${type} agent=${agent} ${JSON.stringify(event.payload || {})}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
} catch (err) {
|
|
75
|
+
if (err.name !== 'AbortError') {
|
|
76
|
+
console.error(`SSE error: ${err.message}`);
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|