opencandle 0.8.0 → 0.9.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/dist/cli-main.js +48 -24
- package/dist/cli-main.js.map +1 -1
- package/dist/pi/session-writer-lock.d.ts +30 -0
- package/dist/pi/session-writer-lock.js +111 -0
- package/dist/pi/session-writer-lock.js.map +1 -0
- package/dist/prompts/workflow-prompts.js +15 -0
- package/dist/prompts/workflow-prompts.js.map +1 -1
- package/dist/routing/classify-intent.js +8 -9
- package/dist/routing/classify-intent.js.map +1 -1
- package/dist/routing/entity-extractor.js +1 -1
- package/dist/routing/entity-extractor.js.map +1 -1
- package/dist/routing/router-llm-client.d.ts +1 -1
- package/dist/routing/router-llm-client.js +1 -1
- package/dist/routing/router-llm-client.js.map +1 -1
- package/dist/routing/router.js +37 -0
- package/dist/routing/router.js.map +1 -1
- package/dist/workflows/compare-assets.js +4 -1
- package/dist/workflows/compare-assets.js.map +1 -1
- package/gui/server/ask-user-bridge.ts +26 -19
- package/gui/server/chat-event-adapter.ts +49 -3
- package/gui/server/http-routes.ts +173 -15
- package/gui/server/invoke-tool.ts +102 -7
- package/gui/server/live-chat-event-adapter.ts +16 -4
- package/gui/server/server.ts +42 -5
- package/gui/server/session-actions.ts +7 -1
- package/gui/server/session-entry-wait.ts +79 -0
- package/gui/server/writer-lock.ts +1 -122
- package/gui/server/ws-hub.ts +25 -0
- package/gui/shared/chat-events.ts +42 -19
- package/gui/shared/event-reducer.ts +41 -26
- package/gui/web/dist/assets/CatalogOverlay-DcTXLc7u.js +1 -0
- package/gui/web/dist/assets/index-DdMnIvZ7.css +2 -0
- package/gui/web/dist/assets/index-YlMaahAS.js +65 -0
- package/gui/web/dist/index.html +2 -2
- package/package.json +15 -15
- package/src/cli-main.ts +64 -27
- package/src/pi/session-writer-lock.ts +156 -0
- package/src/prompts/workflow-prompts.ts +15 -0
- package/src/routing/classify-intent.ts +11 -11
- package/src/routing/entity-extractor.ts +1 -1
- package/src/routing/router-llm-client.ts +2 -1
- package/src/routing/router.ts +46 -0
- package/src/workflows/compare-assets.ts +4 -2
- package/gui/web/dist/assets/CatalogOverlay-CCVKwBUB.js +0 -1
- package/gui/web/dist/assets/index-Dm4Aom2_.js +0 -69
- package/gui/web/dist/assets/index-UzZUg3dx.css +0 -1
package/gui/web/dist/index.html
CHANGED
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
|
9
9
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
|
10
10
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
|
|
11
|
-
<script type="module" crossorigin src="/assets/index-
|
|
12
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
11
|
+
<script type="module" crossorigin src="/assets/index-YlMaahAS.js"></script>
|
|
12
|
+
<link rel="stylesheet" crossorigin href="/assets/index-DdMnIvZ7.css">
|
|
13
13
|
</head>
|
|
14
14
|
<body>
|
|
15
15
|
<div id="root"></div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "opencandle",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Financial trading & investing agent",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"homepage": "https://opencandle.app",
|
|
@@ -128,29 +128,29 @@
|
|
|
128
128
|
"node": ">=22.19.0 <27"
|
|
129
129
|
},
|
|
130
130
|
"dependencies": {
|
|
131
|
-
"@earendil-works/pi-agent-core": "^0.
|
|
132
|
-
"@earendil-works/pi-ai": "^0.
|
|
133
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
134
|
-
"better-sqlite3": "^12.
|
|
131
|
+
"@earendil-works/pi-agent-core": "^0.80.2",
|
|
132
|
+
"@earendil-works/pi-ai": "^0.80.2",
|
|
133
|
+
"@earendil-works/pi-coding-agent": "^0.80.2",
|
|
134
|
+
"better-sqlite3": "^12.11.1",
|
|
135
135
|
"duck-duck-scrape": "^2.2.7",
|
|
136
|
-
"tsx": "^4.22.
|
|
136
|
+
"tsx": "^4.22.4",
|
|
137
137
|
"yahoo-finance2": "^3.15.3"
|
|
138
138
|
},
|
|
139
139
|
"peerDependencies": {
|
|
140
140
|
"@sinclair/typebox": "*"
|
|
141
141
|
},
|
|
142
142
|
"devDependencies": {
|
|
143
|
-
"@agentclientprotocol/claude-agent-acp": "^0.
|
|
144
|
-
"@
|
|
143
|
+
"@agentclientprotocol/claude-agent-acp": "^0.52.0",
|
|
144
|
+
"@agentclientprotocol/codex-acp": "^1.0.0",
|
|
145
|
+
"@biomejs/biome": "^2.5.1",
|
|
145
146
|
"@sinclair/typebox": "^0.34.0",
|
|
146
147
|
"@types/better-sqlite3": "^7.6.13",
|
|
147
|
-
"@types/node": "^
|
|
148
|
-
"
|
|
149
|
-
"
|
|
150
|
-
"playwright-core": "^1.61.0",
|
|
148
|
+
"@types/node": "^26.0.1",
|
|
149
|
+
"acpx": "^0.11.2",
|
|
150
|
+
"playwright-core": "^1.61.1",
|
|
151
151
|
"typescript": "^6.0.3",
|
|
152
|
-
"vite": "^8.0
|
|
153
|
-
"vitest": "^4.1.
|
|
154
|
-
"vitest-evals": "^0.
|
|
152
|
+
"vite": "^8.1.0",
|
|
153
|
+
"vitest": "^4.1.9",
|
|
154
|
+
"vitest-evals": "^0.14.0"
|
|
155
155
|
}
|
|
156
156
|
}
|
package/src/cli-main.ts
CHANGED
|
@@ -17,6 +17,12 @@ import { loadEnv } from "./config.js";
|
|
|
17
17
|
import { handleDoctorCommand } from "./doctor/cli-command.js";
|
|
18
18
|
import { createOpenCandleSession } from "./pi/session.js";
|
|
19
19
|
import { continueOpenCandleSession } from "./pi/session-storage.js";
|
|
20
|
+
import {
|
|
21
|
+
acquireSessionWriterLock,
|
|
22
|
+
refreshSessionWriterLock,
|
|
23
|
+
releaseSessionWriterLock,
|
|
24
|
+
writerLockScopeForSession,
|
|
25
|
+
} from "./pi/session-writer-lock.js";
|
|
20
26
|
|
|
21
27
|
const require = createRequire(import.meta.url);
|
|
22
28
|
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), "..");
|
|
@@ -190,35 +196,64 @@ async function main(): Promise<void> {
|
|
|
190
196
|
initTheme(settingsManager.getTheme(), true);
|
|
191
197
|
|
|
192
198
|
const sessionManager = continueOpenCandleSession(cwd);
|
|
193
|
-
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
settingsManager,
|
|
207
|
-
authStorage,
|
|
208
|
-
modelRegistry,
|
|
209
|
-
sessionManager: opts.sessionManager,
|
|
210
|
-
bindExtensions: false,
|
|
211
|
-
});
|
|
212
|
-
return {
|
|
213
|
-
...result,
|
|
214
|
-
services,
|
|
215
|
-
diagnostics: services.diagnostics,
|
|
216
|
-
};
|
|
217
|
-
},
|
|
218
|
-
{ cwd, agentDir, sessionManager },
|
|
199
|
+
const sessionWriterLockScope = writerLockScopeForSession(sessionManager);
|
|
200
|
+
const sessionWriterLock = await acquireSessionWriterLock(sessionWriterLockScope, "tui");
|
|
201
|
+
if (sessionWriterLock.role !== "writer") {
|
|
202
|
+
console.error(
|
|
203
|
+
`Session is currently being written by ${sessionWriterLock.lock.processKind} (pid ${sessionWriterLock.lock.pid}).`,
|
|
204
|
+
);
|
|
205
|
+
process.exitCode = 1;
|
|
206
|
+
return;
|
|
207
|
+
}
|
|
208
|
+
let activeSessionWriterLockScope = sessionWriterLockScope;
|
|
209
|
+
const writerLockHeartbeat = setInterval(
|
|
210
|
+
() => refreshSessionWriterLock(activeSessionWriterLockScope),
|
|
211
|
+
5000,
|
|
219
212
|
);
|
|
220
213
|
|
|
214
|
+
let runtime: Awaited<ReturnType<typeof createAgentSessionRuntime>> | undefined;
|
|
221
215
|
try {
|
|
216
|
+
runtime = await createAgentSessionRuntime(
|
|
217
|
+
async (opts) => {
|
|
218
|
+
const services = await createAgentSessionServices({
|
|
219
|
+
cwd: opts.cwd,
|
|
220
|
+
agentDir: opts.agentDir,
|
|
221
|
+
authStorage,
|
|
222
|
+
settingsManager,
|
|
223
|
+
modelRegistry,
|
|
224
|
+
});
|
|
225
|
+
const result = await createOpenCandleSession({
|
|
226
|
+
cwd: opts.cwd,
|
|
227
|
+
agentDir: opts.agentDir,
|
|
228
|
+
settingsManager,
|
|
229
|
+
authStorage,
|
|
230
|
+
modelRegistry,
|
|
231
|
+
sessionManager: opts.sessionManager,
|
|
232
|
+
bindExtensions: false,
|
|
233
|
+
});
|
|
234
|
+
return {
|
|
235
|
+
...result,
|
|
236
|
+
services,
|
|
237
|
+
diagnostics: services.diagnostics,
|
|
238
|
+
};
|
|
239
|
+
},
|
|
240
|
+
{ cwd, agentDir, sessionManager },
|
|
241
|
+
);
|
|
242
|
+
runtime.setRebindSession(async (nextSession) => {
|
|
243
|
+
const nextSessionWriterLockScope = writerLockScopeForSession(nextSession.sessionManager);
|
|
244
|
+
if (nextSessionWriterLockScope === activeSessionWriterLockScope) return;
|
|
245
|
+
const nextSessionWriterLock = await acquireSessionWriterLock(
|
|
246
|
+
nextSessionWriterLockScope,
|
|
247
|
+
"tui",
|
|
248
|
+
);
|
|
249
|
+
if (nextSessionWriterLock.role !== "writer") {
|
|
250
|
+
throw new Error(
|
|
251
|
+
`Session is currently being written by ${nextSessionWriterLock.lock.processKind} (pid ${nextSessionWriterLock.lock.pid}).`,
|
|
252
|
+
);
|
|
253
|
+
}
|
|
254
|
+
releaseSessionWriterLock(activeSessionWriterLockScope);
|
|
255
|
+
activeSessionWriterLockScope = nextSessionWriterLockScope;
|
|
256
|
+
});
|
|
222
257
|
const interactiveMode = new InteractiveMode(runtime, {
|
|
223
258
|
modelFallbackMessage: shouldSuppressFallbackMessage
|
|
224
259
|
? undefined
|
|
@@ -226,7 +261,9 @@ async function main(): Promise<void> {
|
|
|
226
261
|
});
|
|
227
262
|
await interactiveMode.run();
|
|
228
263
|
} finally {
|
|
229
|
-
|
|
264
|
+
clearInterval(writerLockHeartbeat);
|
|
265
|
+
releaseSessionWriterLock(activeSessionWriterLockScope);
|
|
266
|
+
await runtime?.dispose();
|
|
230
267
|
}
|
|
231
268
|
}
|
|
232
269
|
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import {
|
|
2
|
+
closeSync,
|
|
3
|
+
mkdirSync,
|
|
4
|
+
openSync,
|
|
5
|
+
readFileSync,
|
|
6
|
+
statSync,
|
|
7
|
+
unlinkSync,
|
|
8
|
+
writeFileSync,
|
|
9
|
+
} from "node:fs";
|
|
10
|
+
import { dirname, join } from "node:path";
|
|
11
|
+
|
|
12
|
+
export type ProcessKind = "tui" | "gui";
|
|
13
|
+
|
|
14
|
+
export interface WriterLock {
|
|
15
|
+
pid: number;
|
|
16
|
+
processKind: ProcessKind;
|
|
17
|
+
acquiredAt: string;
|
|
18
|
+
lastHeartbeat: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export interface AcquireOptions {
|
|
22
|
+
pid?: number;
|
|
23
|
+
staleGraceMs?: number;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export type AcquireResult =
|
|
27
|
+
| { role: "writer"; lock: WriterLock }
|
|
28
|
+
| { role: "follower"; lock: WriterLock };
|
|
29
|
+
|
|
30
|
+
export interface SessionLockScopeSource {
|
|
31
|
+
getSessionFile(): string | undefined;
|
|
32
|
+
getSessionDir(): string;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const DEFAULT_STALE_GRACE_MS = 15_000;
|
|
36
|
+
|
|
37
|
+
export async function acquireWriterLock(
|
|
38
|
+
scopePath: string,
|
|
39
|
+
processKind: ProcessKind,
|
|
40
|
+
options: AcquireOptions = {},
|
|
41
|
+
): Promise<AcquireResult> {
|
|
42
|
+
mkdirSync(dirname(lockPath(scopePath)), { recursive: true });
|
|
43
|
+
const pid = options.pid ?? process.pid;
|
|
44
|
+
const staleGraceMs = options.staleGraceMs ?? DEFAULT_STALE_GRACE_MS;
|
|
45
|
+
|
|
46
|
+
const created = tryCreate(scopePath, processKind, pid);
|
|
47
|
+
if (created) return { role: "writer", lock: created };
|
|
48
|
+
|
|
49
|
+
const existing = readWriterLock(scopePath);
|
|
50
|
+
if (existing && isLockCurrent(existing, staleGraceMs)) {
|
|
51
|
+
return { role: "follower", lock: existing };
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
await sleep(staleGraceMs);
|
|
55
|
+
const afterGrace = readWriterLock(scopePath);
|
|
56
|
+
if (afterGrace && isLockCurrent(afterGrace, staleGraceMs)) {
|
|
57
|
+
return { role: "follower", lock: afterGrace };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
try {
|
|
61
|
+
unlinkSync(lockPath(scopePath));
|
|
62
|
+
} catch {
|
|
63
|
+
// Missing or concurrently removed is fine; the next create decides ownership.
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const recovered = tryCreate(scopePath, processKind, pid);
|
|
67
|
+
if (recovered) return { role: "writer", lock: recovered };
|
|
68
|
+
|
|
69
|
+
const current = readWriterLock(scopePath) ?? afterGrace ?? existing;
|
|
70
|
+
if (!current) throw new Error("Unable to determine active writer lock");
|
|
71
|
+
return { role: "follower", lock: current };
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export function readWriterLock(scopePath: string): WriterLock | null {
|
|
75
|
+
try {
|
|
76
|
+
return JSON.parse(readFileSync(lockPath(scopePath), "utf8")) as WriterLock;
|
|
77
|
+
} catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function refreshWriterLock(scopePath: string, pid = process.pid): void {
|
|
83
|
+
const lock = readWriterLock(scopePath);
|
|
84
|
+
if (!lock || lock.pid !== pid) return;
|
|
85
|
+
writeFileSync(
|
|
86
|
+
lockPath(scopePath),
|
|
87
|
+
JSON.stringify({ ...lock, lastHeartbeat: new Date().toISOString() }, null, 2),
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export function releaseWriterLock(scopePath: string, pid = process.pid): void {
|
|
92
|
+
const lock = readWriterLock(scopePath);
|
|
93
|
+
if (!lock || lock.pid !== pid) return;
|
|
94
|
+
try {
|
|
95
|
+
unlinkSync(lockPath(scopePath));
|
|
96
|
+
} catch {
|
|
97
|
+
// Best effort shutdown cleanup.
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export const acquireSessionWriterLock = acquireWriterLock;
|
|
102
|
+
export const refreshSessionWriterLock = refreshWriterLock;
|
|
103
|
+
export const releaseSessionWriterLock = releaseWriterLock;
|
|
104
|
+
|
|
105
|
+
export function writerLockScopeForSession(sessionManager: SessionLockScopeSource): string {
|
|
106
|
+
return sessionManager.getSessionFile() ?? sessionManager.getSessionDir();
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function tryCreate(scopePath: string, processKind: ProcessKind, pid: number): WriterLock | null {
|
|
110
|
+
const now = new Date().toISOString();
|
|
111
|
+
const lock: WriterLock = { pid, processKind, acquiredAt: now, lastHeartbeat: now };
|
|
112
|
+
try {
|
|
113
|
+
const fd = openSync(lockPath(scopePath), "wx");
|
|
114
|
+
try {
|
|
115
|
+
writeFileSync(fd, JSON.stringify(lock, null, 2));
|
|
116
|
+
} finally {
|
|
117
|
+
closeSync(fd);
|
|
118
|
+
}
|
|
119
|
+
return lock;
|
|
120
|
+
} catch {
|
|
121
|
+
return null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function isPidAlive(pid: number): boolean {
|
|
126
|
+
try {
|
|
127
|
+
process.kill(pid, 0);
|
|
128
|
+
return true;
|
|
129
|
+
} catch {
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function isLockCurrent(lock: WriterLock, staleGraceMs: number): boolean {
|
|
135
|
+
const heartbeat = Date.parse(lock.lastHeartbeat);
|
|
136
|
+
return (
|
|
137
|
+
isPidAlive(lock.pid) && Number.isFinite(heartbeat) && Date.now() - heartbeat <= staleGraceMs
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function lockPath(scopePath: string): string {
|
|
142
|
+
return isFileScope(scopePath) ? `${scopePath}.writer.lock` : join(scopePath, "writer.lock");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function isFileScope(scopePath: string): boolean {
|
|
146
|
+
if (scopePath.endsWith(".jsonl")) return true;
|
|
147
|
+
try {
|
|
148
|
+
return statSync(scopePath).isFile();
|
|
149
|
+
} catch {
|
|
150
|
+
return false;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
function sleep(ms: number): Promise<void> {
|
|
155
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
156
|
+
}
|
|
@@ -455,6 +455,19 @@ macro hedge decision guidance:
|
|
|
455
455
|
- Prioritize the evidence that matters most over ${timeHorizon}: near-term catalysts, earnings/guidance, forward-looking valuation/estimates, sentiment, macro sensitivity, and company-specific risks.
|
|
456
456
|
- Call out evidence that is missing or unavailable, especially forward-looking estimates or company-specific catalysts.`
|
|
457
457
|
: "";
|
|
458
|
+
const actionPlanResponse = timeHorizon
|
|
459
|
+
? `
|
|
460
|
+
- REQUIRED ACTION SECTION: Immediately after the summary verdict and before caveats, include a section exactly titled "### Cautious action plan". Use bullets for preferred tilt, entry conditions, position-sizing caution, downside risk/invalidation trigger, and the missing data that would change the plan for the ${timeHorizon} horizon. If this section is missing, the answer is incomplete.`
|
|
461
|
+
: "";
|
|
462
|
+
const responseHeadingOrder = timeHorizon
|
|
463
|
+
? `
|
|
464
|
+
Use these response headings in this order:
|
|
465
|
+
1. Assumptions
|
|
466
|
+
2. Comparison table
|
|
467
|
+
3. Summary Verdict
|
|
468
|
+
4. Cautious action plan
|
|
469
|
+
5. Caveats`
|
|
470
|
+
: "";
|
|
458
471
|
|
|
459
472
|
const disclosureBlock = buildDisclosureBlock(
|
|
460
473
|
{
|
|
@@ -482,8 +495,10 @@ ${overlapGuidance}
|
|
|
482
495
|
${disclosureBlock}
|
|
483
496
|
|
|
484
497
|
Response format:
|
|
498
|
+
${responseHeadingOrder}
|
|
485
499
|
${ASSUMPTIONS_RESPONSE_INSTRUCTION}
|
|
486
500
|
${tableInstruction}
|
|
487
501
|
- Provide a summary verdict: which is most attractive and why.
|
|
502
|
+
${actionPlanResponse}
|
|
488
503
|
- Note any caveats (different sectors, concentration, market cap disparity, unavailable fundamentals, unavailable forward-looking estimates, etc.).${horizonResponse}`;
|
|
489
504
|
}
|
|
@@ -78,11 +78,7 @@ const RULES: Rule[] = [
|
|
|
78
78
|
confidence: 0.9,
|
|
79
79
|
test: (input, entities) => {
|
|
80
80
|
const lower = input.toLowerCase();
|
|
81
|
-
const hasOptionKeywords =
|
|
82
|
-
/\bcalls?\b/.test(lower) ||
|
|
83
|
-
/\bputs?\b/.test(lower) ||
|
|
84
|
-
/\boption(?:s)?\s*chain\b/.test(lower) ||
|
|
85
|
-
/\boptions?\b/.test(lower);
|
|
81
|
+
const hasOptionKeywords = hasOptionKeywordsInText(lower);
|
|
86
82
|
const hasCompareKeywords =
|
|
87
83
|
/\bcompare\b/.test(lower) ||
|
|
88
84
|
/\bvs\.?\b/.test(lower) ||
|
|
@@ -137,12 +133,7 @@ const RULES: Rule[] = [
|
|
|
137
133
|
confidence: 0.95,
|
|
138
134
|
test: (input, entities) => {
|
|
139
135
|
const lower = input.toLowerCase();
|
|
140
|
-
|
|
141
|
-
/\bcalls?\b/.test(lower) ||
|
|
142
|
-
/\bputs?\b/.test(lower) ||
|
|
143
|
-
/\boption(?:s)?\s*chain\b/.test(lower) ||
|
|
144
|
-
/\boptions?\b/.test(lower);
|
|
145
|
-
return hasOptionKeywords && entities.symbols.length >= 1;
|
|
136
|
+
return hasOptionKeywordsInText(lower) && entities.symbols.length >= 1;
|
|
146
137
|
},
|
|
147
138
|
},
|
|
148
139
|
// Stateful portfolio/watchlist/alert/prediction mutations must not be
|
|
@@ -303,6 +294,15 @@ function isPortfolioEvaluationRequest(input: string): boolean {
|
|
|
303
294
|
);
|
|
304
295
|
}
|
|
305
296
|
|
|
297
|
+
function hasOptionKeywordsInText(lower: string): boolean {
|
|
298
|
+
return (
|
|
299
|
+
/\bcalls?\b(?!\s+out\b)/.test(lower) ||
|
|
300
|
+
/\bputs?\b/.test(lower) ||
|
|
301
|
+
/\boption(?:s)?\s*chain\b/.test(lower) ||
|
|
302
|
+
/\boptions?\b/.test(lower)
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
|
|
306
306
|
function isStatefulTrackingRequest(input: string): boolean {
|
|
307
307
|
const lower = input.toLowerCase();
|
|
308
308
|
const hasPortfolioConstructionIntent =
|
|
@@ -451,7 +451,7 @@ function extractCostBasis(input: string): number | undefined {
|
|
|
451
451
|
|
|
452
452
|
function extractDirection(input: string): "bullish" | "bearish" | undefined {
|
|
453
453
|
const lower = input.toLowerCase();
|
|
454
|
-
if (/\bcalls?\b/.test(lower) || /\bbullish\b/.test(lower)) return "bullish";
|
|
454
|
+
if (/\bcalls?\b(?!\s+out\b)/.test(lower) || /\bbullish\b/.test(lower)) return "bullish";
|
|
455
455
|
if (/\bputs?\b/.test(lower) || /\bbearish\b/.test(lower)) return "bearish";
|
|
456
456
|
return undefined;
|
|
457
457
|
}
|
package/src/routing/router.ts
CHANGED
|
@@ -276,6 +276,32 @@ export function postProcessRouterOutput(text: string, output: RouterOutput): Rou
|
|
|
276
276
|
};
|
|
277
277
|
}
|
|
278
278
|
|
|
279
|
+
if (
|
|
280
|
+
next.workflow === "options_screener" &&
|
|
281
|
+
next.entities.symbols.length >= 2 &&
|
|
282
|
+
isPlainMultiAssetComparisonRequest(text)
|
|
283
|
+
) {
|
|
284
|
+
diagnostics.push({
|
|
285
|
+
code: "options_comparison_corrected_to_compare_assets",
|
|
286
|
+
message:
|
|
287
|
+
"explicit multi-asset comparison without option contract language should use compare_assets",
|
|
288
|
+
});
|
|
289
|
+
next = {
|
|
290
|
+
...next,
|
|
291
|
+
routeKind: "workflow_dispatch",
|
|
292
|
+
route: "workflow",
|
|
293
|
+
workflow: "compare_assets",
|
|
294
|
+
missing_required: [],
|
|
295
|
+
entities: {
|
|
296
|
+
...next.entities,
|
|
297
|
+
direction: undefined,
|
|
298
|
+
dteHint: undefined,
|
|
299
|
+
optionStrategy: undefined,
|
|
300
|
+
},
|
|
301
|
+
diagnostics,
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
|
|
279
305
|
// Legacy rules may recover a primary route only when the LLM router path has
|
|
280
306
|
// already failed validation. Otherwise they are limited to enrichment and
|
|
281
307
|
// narrow corrections below.
|
|
@@ -718,6 +744,26 @@ function isOptionsEducationOrSuitabilityRequest(text: string): boolean {
|
|
|
718
744
|
);
|
|
719
745
|
}
|
|
720
746
|
|
|
747
|
+
function isPlainMultiAssetComparisonRequest(text: string): boolean {
|
|
748
|
+
const lower = text.toLowerCase();
|
|
749
|
+
const hasCompareIntent =
|
|
750
|
+
/\bcompare\b/.test(lower) ||
|
|
751
|
+
/\bvs\.?\b/.test(lower) ||
|
|
752
|
+
/\bversus\b/.test(lower) ||
|
|
753
|
+
/\bwhich\s+is\s+better\b/.test(lower);
|
|
754
|
+
return hasCompareIntent && !hasExplicitOptionContractLanguage(lower);
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function hasExplicitOptionContractLanguage(lower: string): boolean {
|
|
758
|
+
return (
|
|
759
|
+
/\bcalls?\b(?!\s+out\b)/.test(lower) ||
|
|
760
|
+
/\bputs?\b/.test(lower) ||
|
|
761
|
+
/\boption(?:s)?\s*chain\b/.test(lower) ||
|
|
762
|
+
/\boptions?\b/.test(lower) ||
|
|
763
|
+
/\b(?:strike|expiration|dte|premium|delta|theta|greeks?|contract)\b/.test(lower)
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
|
|
721
767
|
function isSpecificOptionContractSelectionRequest(text: string): boolean {
|
|
722
768
|
const lower = text.toLowerCase();
|
|
723
769
|
return (
|
|
@@ -62,7 +62,9 @@ export function buildCompareAssetsWorkflowDefinition(
|
|
|
62
62
|
: timeHorizon
|
|
63
63
|
? `End with a concise verdict on which asset best fits the ${timeHorizon} horizon and why.`
|
|
64
64
|
: "End with a concise verdict on which asset looks strongest right now and why.";
|
|
65
|
-
|
|
65
|
+
const actionPlanGuidance = timeHorizon
|
|
66
|
+
? `\n- Required action section: immediately after the summary verdict and before caveats, add a section exactly titled "Cautious action plan" for the ${timeHorizon} horizon. Include preferred tilt, entry conditions, position-sizing caution, downside risk/invalidation trigger, and the missing data that would change the plan. Do not end at Caveats.`
|
|
67
|
+
: "";
|
|
66
68
|
return {
|
|
67
69
|
workflowType: "compare_assets",
|
|
68
70
|
steps: [
|
|
@@ -76,7 +78,7 @@ export function buildCompareAssetsWorkflowDefinition(
|
|
|
76
78
|
`Now present the side-by-side comparison for ${symbols}:
|
|
77
79
|
- Keep any unavailable fundamentals marked as unavailable instead of retrying the same failed provider calls.
|
|
78
80
|
- Use the ${evidenceList} you already fetched to finish the comparison even if some fundamentals are missing.
|
|
79
|
-
- ${verdictInstruction}${horizonGuidance}${macroHedgeGuidance}${interestRateGuidance}${overlapGuidance}`,
|
|
81
|
+
- ${verdictInstruction}${horizonGuidance}${macroHedgeGuidance}${interestRateGuidance}${overlapGuidance}${actionPlanGuidance}`,
|
|
80
82
|
{
|
|
81
83
|
requiredInputs: ["asset_data"],
|
|
82
84
|
expectedOutputs: ["comparison_summary"],
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{_ as e,a as t,c as n,d as r,f as i,g as a,h as o,i as s,l as c,m as l,n as u,o as d,p as f,r as p,s as m,t as h,u as g,v as _,y as v}from"./index-Dm4Aom2_.js";var y=o(`arrow-right`,[[`path`,{d:`M5 12h14`,key:`1ays0h`}],[`path`,{d:`m12 5 7 7-7 7`,key:`xquz4c`}]]),b=o(`chevron-left`,[[`path`,{d:`m15 18-6-6 6-6`,key:`1wnfg3`}]]),x=o(`clipboard`,[[`rect`,{width:`8`,height:`4`,x:`8`,y:`2`,rx:`1`,ry:`1`,key:`tgr4d6`}],[`path`,{d:`M16 4h2a2 2 0 0 1 2 2v14a2 2 0 0 1-2 2H6a2 2 0 0 1-2-2V6a2 2 0 0 1 2-2h2`,key:`116196`}]]),ee=o(`earth`,[[`path`,{d:`M21.54 15H17a2 2 0 0 0-2 2v4.54`,key:`1djwo0`}],[`path`,{d:`M7 3.34V5a3 3 0 0 0 3 3a2 2 0 0 1 2 2c0 1.1.9 2 2 2a2 2 0 0 0 2-2c0-1.1.9-2 2-2h3.17`,key:`1tzkfa`}],[`path`,{d:`M11 21.95V18a2 2 0 0 0-2-2a2 2 0 0 1-2-2v-1a2 2 0 0 0-2-2H2.05`,key:`14pb5j`}],[`circle`,{cx:`12`,cy:`12`,r:`10`,key:`1mglay`}]]),te=o(`eye-off`,[[`path`,{d:`M10.733 5.076a10.744 10.744 0 0 1 11.205 6.575 1 1 0 0 1 0 .696 10.747 10.747 0 0 1-1.444 2.49`,key:`ct8e1f`}],[`path`,{d:`M14.084 14.158a3 3 0 0 1-4.242-4.242`,key:`151rxh`}],[`path`,{d:`M17.479 17.499a10.75 10.75 0 0 1-15.417-5.151 1 1 0 0 1 0-.696 10.75 10.75 0 0 1 4.446-5.143`,key:`13bj9a`}],[`path`,{d:`m2 2 20 20`,key:`1ooewy`}]]),ne=o(`eye`,[[`path`,{d:`M2.062 12.348a1 1 0 0 1 0-.696 10.75 10.75 0 0 1 19.876 0 1 1 0 0 1 0 .696 10.75 10.75 0 0 1-19.876 0`,key:`1nclc0`}],[`circle`,{cx:`12`,cy:`12`,r:`3`,key:`1v7zrd`}]]),S=o(`play`,[[`path`,{d:`M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z`,key:`10ikf1`}]]),C=o(`sparkles`,[[`path`,{d:`M11.017 2.814a1 1 0 0 1 1.966 0l1.051 5.558a2 2 0 0 0 1.594 1.594l5.558 1.051a1 1 0 0 1 0 1.966l-5.558 1.051a2 2 0 0 0-1.594 1.594l-1.051 5.558a1 1 0 0 1-1.966 0l-1.051-5.558a2 2 0 0 0-1.594-1.594l-5.558-1.051a1 1 0 0 1 0-1.966l5.558-1.051a2 2 0 0 0 1.594-1.594z`,key:`1s2grr`}],[`path`,{d:`M20 2v4`,key:`1rf3ol`}],[`path`,{d:`M22 4h-4`,key:`gwowj6`}],[`circle`,{cx:`4`,cy:`20`,r:`2`,key:`6kqj1y`}]]),w=o(`terminal`,[[`path`,{d:`M12 19h8`,key:`baeox8`}],[`path`,{d:`m4 17 6-6-6-6`,key:`1yngyt`}]]),T=v(_(),1),re=[{value:`1mo`,label:`1M`},{value:`3mo`,label:`3M`},{value:`6mo`,label:`6M`},{value:`1y`,label:`1Y`},{value:`2y`,label:`2Y`},{value:`5y`,label:`5Y`},{value:`max`,label:`Max`}],ie=[{value:`6mo`,label:`6M`},{value:`1y`,label:`1Y`},{value:`2y`,label:`2Y`}],E=[{value:`hours`,label:`Hours`},{value:`day`,label:`Day`},{value:`week`,label:`Week`},{value:`month`,label:`Month`}],D=[{value:6,label:`6h`},{value:24,label:`24h`},{value:72,label:`3d`},{value:168,label:`7d`}],O=[{value:7,label:`7d`},{value:30,label:`30d`},{value:90,label:`90d`},{value:180,label:`6M`},{value:365,label:`1Y`}],k=e();function A({label:e,hint:t,required:n=!1,children:r,className:i}){return(0,k.jsxs)(`label`,{className:a(`grid gap-1.5`,i),children:[(0,k.jsxs)(`span`,{className:`flex items-baseline justify-between gap-3 text-xs font-medium text-foreground`,children:[(0,k.jsxs)(`span`,{children:[e,n?(0,k.jsxs)(`span`,{className:`text-foreground/40`,"aria-hidden":`true`,children:[` `,`*`]}):null]}),t?(0,k.jsx)(`span`,{className:`text-[11px] font-normal text-muted-foreground`,children:t}):null]}),r]})}function ae({value:e,onChange:t,options:n,ariaLabel:r}){return(0,k.jsx)(`div`,{role:`radiogroup`,"aria-label":r,className:`inline-flex h-9 items-center rounded-md border border-border bg-card p-0.5`,children:n.map(n=>{let r=n.value===e;return(0,k.jsx)(`button`,{type:`button`,role:`radio`,"aria-checked":r,onClick:()=>t(n.value),className:a(`inline-flex h-8 min-w-9 items-center justify-center rounded-[4px] px-2.5 text-xs font-medium tabular-nums transition-colors`,r?`bg-foreground text-background`:`text-muted-foreground hover:text-foreground`),children:n.label},n.value)})})}function oe({value:e,onChange:t,options:n,placeholder:r,ariaLabel:i}){return(0,k.jsxs)(`div`,{className:`relative`,children:[(0,k.jsxs)(`select`,{"aria-label":i,value:e??``,onChange:e=>t(e.target.value||void 0),className:`h-9 w-full appearance-none rounded-md border border-border bg-card px-3 pr-9 text-sm text-foreground transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background`,children:[r?(0,k.jsx)(`option`,{value:``,disabled:!0,hidden:!0,children:r}):null,n.map(e=>(0,k.jsx)(`option`,{value:e.value,children:e.label},e.value))]}),(0,k.jsx)(f,{"aria-hidden":`true`,className:`pointer-events-none absolute right-2.5 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground`})]})}function se({value:e,onChange:t,presets:n,suffix:r,min:i,max:o,step:s=1,placeholder:c}){let l=n.some(t=>t.value===e);return(0,k.jsxs)(`div`,{className:`grid gap-2`,children:[(0,k.jsx)(`div`,{className:`flex flex-wrap items-center gap-1.5`,children:n.map(n=>(0,k.jsx)(`button`,{type:`button`,onClick:()=>t(n.value),className:a(`inline-flex h-7 items-center rounded-full border px-2.5 text-xs font-medium tabular-nums transition-colors`,n.value===e?`border-foreground bg-foreground text-background`:`border-border bg-card text-muted-foreground hover:border-border hover:text-foreground`),children:n.label},String(n.value)))}),(0,k.jsxs)(`div`,{className:`relative w-32`,children:[(0,k.jsx)(p,{type:`number`,inputMode:`numeric`,value:l?``:e??``,min:i,max:o,step:s,placeholder:c??`Custom`,onChange:e=>{t(e.target.value===``?void 0:Number(e.target.value))},className:`h-8 pr-8 text-xs tabular-nums`}),r?(0,k.jsx)(`span`,{className:`pointer-events-none absolute right-2 top-1/2 -translate-y-1/2 text-[11px] text-muted-foreground`,children:r}):null]})]})}function ce({value:e,onChange:t,lookup:n,placeholder:r=`AAPL`,ariaLabel:i}){let[a,o]=(0,T.useState)(!1),[s,c]=(0,T.useState)({query:``,items:[]}),[l,u]=(0,T.useState)(``),d=(0,T.useRef)(null),f=String(e||``).trim(),m=s.query===f?s.items:[],h=l===f&&f.length>0;return(0,T.useEffect)(()=>{if(n&&!(f.length<1))return d.current&&clearTimeout(d.current),d.current=setTimeout(async()=>{u(f);try{c({query:f,items:(await n(f)).slice(0,6)})}catch{c({query:f,items:[]})}finally{u(e=>e===f?``:e)}},180),()=>{d.current&&clearTimeout(d.current)}},[f,n]),(0,k.jsxs)(`div`,{className:`relative`,children:[(0,k.jsx)(p,{"aria-label":i,value:e??``,placeholder:r,onChange:e=>t(e.target.value.toUpperCase()),onFocus:()=>o(!0),onBlur:()=>setTimeout(()=>o(!1),120),className:`h-9 tabular-nums`,autoCapitalize:`characters`}),a&&m.length>0?(0,k.jsx)(`div`,{className:`absolute left-0 right-0 top-full z-20 mt-1 max-h-60 overflow-auto rounded-md border border-border bg-card shadow-subtle-sm`,children:m.map(e=>(0,k.jsxs)(`button`,{type:`button`,onMouseDown:e=>e.preventDefault(),onClick:()=>{t(e.symbol),o(!1)},className:`flex w-full items-center justify-between gap-3 px-3 py-2 text-left text-sm hover:bg-secondary`,children:[(0,k.jsx)(`span`,{className:`font-medium tabular-nums text-foreground`,children:e.symbol}),(0,k.jsx)(`span`,{className:`truncate text-xs text-muted-foreground`,children:e.name})]},e.symbol))}):null,h?(0,k.jsx)(`span`,{className:`absolute right-3 top-1/2 -translate-y-1/2 text-[10px] uppercase tracking-wider text-muted-foreground`,children:`…`}):null]})}function le({value:e=[],onChange:n,placeholder:r=`Add ticker`,min:i,max:a,ariaLabel:o=`Ticker symbols`}){let[s,c]=(0,T.useState)(``),l=a!=null&&e.length>=a,u=()=>{let t=s.trim().toUpperCase();if(t){if(e.includes(t)){c(``);return}l||(n([...e,t]),c(``))}},f=t=>n(e.filter(e=>e!==t));return(0,k.jsxs)(`div`,{children:[(0,k.jsxs)(`div`,{className:`flex min-h-9 flex-wrap items-center gap-1.5 rounded-md border border-border bg-card px-2 py-1.5 focus-within:ring-2 focus-within:ring-ring focus-within:ring-offset-2 focus-within:ring-offset-background`,children:[e.map(e=>(0,k.jsxs)(`span`,{className:`inline-flex items-center gap-1 rounded-md border border-border bg-secondary px-1.5 py-0.5 text-xs font-medium tabular-nums text-foreground`,children:[e,(0,k.jsx)(`button`,{type:`button`,"aria-label":`Remove ${e}`,onClick:()=>f(e),className:`text-muted-foreground hover:text-foreground`,children:(0,k.jsx)(d,{className:`h-3 w-3`})})]},e)),(0,k.jsx)(`input`,{"aria-label":o,value:s,onChange:e=>c(e.target.value.toUpperCase()),onKeyDown:t=>{t.key===`Enter`||t.key===`,`?(t.preventDefault(),u()):t.key===`Backspace`&&!s&&e.length>0&&(t.preventDefault(),n(e.slice(0,-1)))},placeholder:e.length===0?r:``,disabled:l,className:`min-w-[80px] flex-1 bg-transparent py-1 text-xs tabular-nums text-foreground outline-none placeholder:text-muted-foreground disabled:opacity-40`,autoCapitalize:`characters`}),s.trim()?(0,k.jsx)(t,{type:`button`,variant:`ghost`,size:`icon-xs`,"aria-label":`Add ticker`,onClick:u,children:(0,k.jsx)(g,{})}):null]}),i!=null&&e.length<i?(0,k.jsxs)(`p`,{className:`mt-1 text-[11px] text-muted-foreground`,children:[`Add at least `,i,` symbol`,i===1?``:`s`,`.`]}):null,a==null?null:(0,k.jsxs)(`p`,{className:`mt-1 text-[11px] text-muted-foreground tabular-nums`,children:[e.length,`/`,a]})]})}function ue({value:e=[],onChange:t,options:n}){let r=n=>{e.includes(n)?t(e.filter(e=>e!==n)):t([...e,n])};return(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:n.map(t=>{let n=e.includes(t.value);return(0,k.jsxs)(`button`,{type:`button`,onClick:()=>r(t.value),className:a(`inline-flex h-7 items-center gap-1 rounded-full border px-2.5 text-xs font-medium transition-colors`,n?`border-foreground bg-foreground text-background`:`border-border bg-card text-muted-foreground hover:text-foreground`),children:[n?(0,k.jsx)(l,{className:`h-3 w-3`,"aria-hidden":`true`}):null,t.label]},t.value)})})}function de({value:e,onChange:t,min:n,max:r,placeholder:i=`YYYY-MM-DD`}){return(0,k.jsx)(p,{type:`date`,value:e??``,min:n,max:r,placeholder:i,onChange:e=>t(e.target.value||void 0),className:`h-9 tabular-nums`})}function fe({value:e,onChange:t,placeholder:n,rows:r=3,maxLength:i,ariaLabel:a=`Text input`}){return(0,k.jsxs)(`div`,{children:[(0,k.jsx)(`textarea`,{"aria-label":a,value:e??``,onChange:e=>t(e.target.value),placeholder:n,maxLength:i,rows:r,className:`block w-full resize-y rounded-md border border-border bg-card px-3 py-2 text-sm text-foreground placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background`}),i?(0,k.jsxs)(`div`,{className:`mt-1 text-right text-[11px] tabular-nums text-muted-foreground`,children:[(e||``).length,`/`,i]}):null]})}function pe({value:e,onChange:t,currency:n=`USD`,min:r=0,placeholder:i=`0`}){let[a,o]=(0,T.useState)(!1),[s,c]=(0,T.useState)(j(e,!1));(0,T.useEffect)(()=>{a||c(j(e,!1))},[e,a]);let l=me(n),u=e=>{if(o(!1),!e||!e.replace(/[^0-9.]/g,``)){t(void 0),c(``);return}let n=Number(e.replace(/[^0-9.]/g,``));Number.isFinite(n)&&(t(n),c(j(n,!1)))};return(0,k.jsxs)(`div`,{className:`relative`,children:[(0,k.jsx)(`span`,{className:`pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground`,children:l}),(0,k.jsx)(p,{value:a?s:j(e,!1),inputMode:`decimal`,placeholder:i,onChange:e=>c(e.target.value.replace(/[^0-9.]/g,``)),onFocus:()=>{o(!0),c(e==null?``:String(e))},onBlur:e=>u(e.target.value),min:r,className:`h-9 pl-7 tabular-nums`})]})}function j(e,t){if(e==null||e===``)return``;let n=Number(e);return Number.isFinite(n)?t?String(n):n.toLocaleString(`en-US`):String(e)}function me(e){return!e||e===`USD`||e===`CAD`||e===`AUD`?`$`:e===`EUR`?`€`:e===`GBP`?`£`:e===`JPY`?`¥`:e}function he({value:e,onChange:t,min:n,max:r,step:i=.5,placeholder:a}){return(0,k.jsxs)(`div`,{className:`relative`,children:[(0,k.jsx)(p,{type:`number`,inputMode:`decimal`,value:e==null||e===``?``:String(Number((Number(e)*100).toFixed(4))),placeholder:a,min:n,max:r,step:i,onChange:e=>{let n=e.target.value;if(n===``){t(void 0);return}let r=Number(n);Number.isFinite(r)&&t(r/100)},className:`h-9 pr-7 tabular-nums`}),(0,k.jsx)(`span`,{className:`pointer-events-none absolute right-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground`,children:`%`})]})}function ge({suggestions:e,onPick:t,label:n=`Suggestions`}){return e?.length?(0,k.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,k.jsx)(`span`,{className:`text-[11px] font-medium uppercase tracking-wider text-muted-foreground`,children:n}),(0,k.jsx)(`div`,{className:`flex flex-wrap gap-1.5`,children:e.map(e=>(0,k.jsx)(`button`,{type:`button`,onClick:()=>t(e.value||e.label),className:`inline-flex h-7 items-center rounded-full border border-border bg-card px-2.5 text-xs font-medium text-muted-foreground transition-colors hover:text-foreground`,children:e.label},e.value||e.label))})]}):null}var _e={DAYS_PRESETS:O,HOURS_PRESETS:D,RANGE_OPTIONS:re,PERIOD_OPTIONS:ie,FRESHNESS_OPTIONS:E};function M(e){return typeof e==`string`?_e[e]??[]:e??[]}function N({field:e,value:t,onChange:n,lookupSymbol:r}){let i=t=>n(e.name,t);switch(e.label,e.required,e.helper&&e.helper,e.kind){case`symbol`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(ce,{value:t,onChange:i,lookup:r,placeholder:e.placeholder,ariaLabel:e.label})});case`symbols`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(le,{value:t||[],onChange:i,min:e.min,max:e.max,placeholder:e.placeholder,ariaLabel:e.label})});case`segmented`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(ae,{value:t,onChange:i,options:M(e.options),ariaLabel:e.label})});case`select`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(oe,{value:t,onChange:i,options:M(e.options),placeholder:e.placeholder,ariaLabel:e.label})});case`number-chips`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(se,{value:t,onChange:i,presets:M(e.presets),suffix:e.suffix,min:e.min,max:e.max,step:e.step,placeholder:e.placeholder})});case`multi-chips`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(ue,{value:t||[],onChange:i,options:M(e.options)})});case`date`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(de,{value:t,onChange:i,min:e.min,max:e.max})});case`freetext`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(fe,{value:t,onChange:i,placeholder:e.placeholder,maxLength:e.maxLength,rows:e.rows,ariaLabel:e.label})});case`money`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(pe,{value:t,onChange:i,currency:e.currency,placeholder:e.placeholder})});case`percent`:return(0,k.jsx)(A,{label:e.label,hint:e.helper,required:e.required,children:(0,k.jsx)(he,{value:t,onChange:i,min:e.min,max:e.max,step:e.step,placeholder:e.placeholder})});default:return(0,k.jsxs)(A,{label:e.label,hint:e.helper,required:e.required,children:[(0,k.jsx)(p,{value:t??``,placeholder:e.placeholder,onChange:e=>i(e.target.value),className:`h-9`}),e.suggestions?.length?(0,k.jsx)(`div`,{className:`mt-2`,children:(0,k.jsx)(ge,{suggestions:e.suggestions,onPick:i,label:`Try`})}):null]})}}function P(e){let t={};for(let n of e)n.default!==void 0&&(t[n.name]=n.default);return t}function F(e,t){let n=[];for(let r of e){if(!r.required)continue;let e=t[r.name];if(e==null||e===``){n.push(`${r.label} is required.`);continue}Array.isArray(e)&&(e.length===0?n.push(`${r.label} is required.`):r.min!=null&&e.length<r.min&&n.push(`${r.label} needs at least ${r.min} entr${r.min===1?`y`:`ies`}.`))}return n}var I=(e={})=>({name:`symbol`,kind:`symbol`,label:`Symbol`,required:!0,default:`NVDA`,placeholder:`AAPL`,...e}),L=(e={})=>({name:`query`,kind:`text`,label:`Ticker or topic`,required:!0,placeholder:`AAPL or AI infrastructure`,...e}),ve={search_ticker:[{name:`query`,kind:`text`,label:`Search query`,required:!0,placeholder:`apple, AAPL, ethereum…`,helper:`Company name, ticker, or crypto. Returns the best matches.`}],get_stock_quote:[I()],get_stock_history:[I(),{name:`range`,kind:`segmented`,label:`Range`,default:`6mo`,options:`RANGE_OPTIONS`},{name:`interval`,kind:`select`,label:`Interval`,default:`1d`,options:[{value:`1d`,label:`Daily`},{value:`1wk`,label:`Weekly`},{value:`1mo`,label:`Monthly`},{value:`1h`,label:`Hourly`},{value:`5m`,label:`5 min`}]}],get_crypto_price:[{name:`id`,kind:`text`,label:`Coin ID`,required:!0,default:`bitcoin`,placeholder:`bitcoin, ethereum, solana`,helper:`CoinGecko coin id (lowercase, hyphenated).`}],get_crypto_history:[{name:`id`,kind:`text`,label:`Coin ID`,required:!0,default:`bitcoin`,placeholder:`bitcoin`,helper:`CoinGecko coin id.`},{name:`days`,kind:`number-chips`,label:`History window`,default:180,presets:`DAYS_PRESETS`,suffix:`days`,helper:`1, 7, 14, 30, 90, 180, 365, or 'max'.`}],get_company_overview:[I()],get_financials:[I(),{name:`statement`,kind:`select`,label:`Statement`,default:`income`,options:[{value:`income`,label:`Income statement`},{value:`balance`,label:`Balance sheet`},{value:`cashflow`,label:`Cash flow`}]}],get_earnings:[I()],calculate_dcf:[I(),{name:`growth_rate`,kind:`percent`,label:`FCF growth rate`,helper:`Annual. Estimated from history if blank.`},{name:`discount_rate`,kind:`percent`,label:`Discount rate (WACC)`,default:.1,helper:`Default 10%.`},{name:`terminal_growth`,kind:`percent`,label:`Terminal growth`,default:.03,helper:`Default 3%.`},{name:`projection_years`,kind:`number-chips`,label:`Projection years`,default:5,presets:[{value:3,label:`3y`},{value:5,label:`5y`},{value:7,label:`7y`},{value:10,label:`10y`}],suffix:`yrs`}],compare_companies:[{name:`symbols`,kind:`symbols`,label:`Tickers`,required:!0,min:2,max:6,default:[`AAPL`,`MSFT`,`GOOGL`],helper:`Pick 2 to 6 tickers to compare side by side.`}],get_sec_filings:[I(),{name:`form_types`,kind:`multi-chips`,label:`Filing types`,default:[`10-K`,`10-Q`,`8-K`],options:[{value:`10-K`,label:`10-K (annual)`},{value:`10-Q`,label:`10-Q (quarterly)`},{value:`8-K`,label:`8-K (material)`},{value:`S-1`,label:`S-1`},{value:`DEF 14A`,label:`Proxy (DEF 14A)`}]},{name:`limit`,kind:`number-chips`,label:`Max results`,default:10,presets:[{value:5,label:`5`},{value:10,label:`10`},{value:25,label:`25`},{value:50,label:`50`}]}],get_economic_data:[{name:`series_id`,kind:`text`,label:`FRED series`,required:!0,default:`CPIAUCSL`,placeholder:`CPIAUCSL`,helper:`Common: CPIAUCSL (CPI), DGS10 (10Y), UNRATE (unemployment), FEDFUNDS.`,suggestions:[{value:`CPIAUCSL`,label:`CPI`},{value:`DGS10`,label:`10Y Treasury`},{value:`UNRATE`,label:`Unemployment`},{value:`FEDFUNDS`,label:`Fed Funds`},{value:`GDP`,label:`GDP`}]},{name:`limit`,kind:`number-chips`,label:`Observations`,default:30,presets:[{value:12,label:`12`},{value:30,label:`30`},{value:60,label:`60`},{value:120,label:`120`}]}],get_fear_greed:[],get_technical_indicators:[I(),{name:`range`,kind:`segmented`,label:`Range`,default:`1y`,options:[{value:`3mo`,label:`3M`},{value:`6mo`,label:`6M`},{value:`1y`,label:`1Y`},{value:`2y`,label:`2Y`}]}],backtest_strategy:[I(),{name:`strategy`,kind:`select`,label:`Strategy`,required:!0,default:`sma_crossover`,options:[{value:`sma_crossover`,label:`SMA crossover (20/50)`},{value:`rsi_mean_reversion`,label:`RSI mean reversion (30/70)`}]},{name:`period`,kind:`segmented`,label:`Lookback`,default:`2y`,options:[{value:`1y`,label:`1Y`},{value:`2y`,label:`2Y`},{value:`5y`,label:`5Y`}]}],manage_portfolio:[{name:`action`,kind:`segmented`,label:`Action`,required:!0,default:`check`,options:[{value:`add`,label:`Add`},{value:`remove`,label:`Remove`},{value:`check`,label:`Check`},{value:`list`,label:`List`}]},I({required:!1,helper:`Required for add/remove.`}),{name:`shares`,kind:`number-chips`,label:`Shares`,presets:[{value:10,label:`10`},{value:100,label:`100`},{value:500,label:`500`}],helper:`Required when adding a position.`},{name:`avg_cost`,kind:`money`,label:`Average cost basis`,helper:`Per share, in your portfolio currency.`}],watchlist:[{name:`action`,kind:`segmented`,label:`Action`,required:!0,default:`check`,options:[{value:`add`,label:`Add`},{value:`remove`,label:`Remove`},{value:`check`,label:`Check`}]},I({required:!1}),{name:`target_price`,kind:`money`,label:`Target (alert ↑)`},{name:`stop_price`,kind:`money`,label:`Stop (alert ↓)`}],analyze_correlation:[{name:`symbols`,kind:`symbols`,label:`Tickers`,required:!0,min:2,max:12,default:[`SPY`,`QQQ`,`TLT`],helper:`2 or more tickers.`},{name:`period`,kind:`segmented`,label:`Window`,default:`1y`,options:`PERIOD_OPTIONS`}],analyze_risk:[I(),{name:`period`,kind:`segmented`,label:`Window`,default:`1y`,options:`PERIOD_OPTIONS`}],predict_returns:[{name:`symbols`,kind:`symbols`,label:`Tickers`,required:!0,min:1,max:8,default:[`NVDA`,`AAPL`],helper:`Forecast 1-week and 1-month return ranges.`}],get_option_chain:[I(),{name:`expiration`,kind:`date`,label:`Expiration`,helper:`Defaults to nearest expiration.`},{name:`type`,kind:`segmented`,label:`Type`,options:[{value:``,label:`Both`},{value:`call`,label:`Calls`},{value:`put`,label:`Puts`}]}],get_reddit_sentiment:[{name:`subreddit`,kind:`text`,label:`Subreddit`,placeholder:`wallstreetbets, stocks, all`,helper:`Leave blank to search defaults.`},{name:`query`,kind:`text`,label:`Filter query`,placeholder:`AAPL or 'rate cuts'`}],get_twitter_sentiment:[L(),{name:`limit`,kind:`number-chips`,label:`Tweets`,default:50,presets:[{value:25,label:`25`},{value:50,label:`50`},{value:100,label:`100`},{value:200,label:`200`}]},{name:`hours`,kind:`number-chips`,label:`Lookback`,default:24,presets:`HOURS_PRESETS`,suffix:`hr`}],get_web_search:[L({label:`Search query`}),{name:`category`,kind:`segmented`,label:`Category`,default:`news`,options:[{value:`news`,label:`News`},{value:`general`,label:`General`}]},{name:`freshness`,kind:`segmented`,label:`Freshness`,default:`day`,options:`FRESHNESS_OPTIONS`}],get_web_sentiment:[L(),{name:`freshness`,kind:`segmented`,label:`Freshness`,default:`day`,options:`FRESHNESS_OPTIONS`},{name:`limit`,kind:`number-chips`,label:`Articles`,default:10,presets:[{value:5,label:`5`},{value:10,label:`10`},{value:20,label:`20`}]}],get_sentiment_trend:[L(),{name:`days`,kind:`number-chips`,label:`Days of history`,default:7,presets:[{value:3,label:`3d`},{value:7,label:`7d`},{value:14,label:`14d`},{value:30,label:`30d`}]},{name:`source`,kind:`select`,label:`Source`,placeholder:`All sources`,options:[{value:`twitter`,label:`Twitter`},{value:`reddit`,label:`Reddit`},{value:`web`,label:`Web`},{value:`finnhub`,label:`Finnhub`}]}],get_sentiment_summary:[L(),{name:`hours`,kind:`number-chips`,label:`Lookback`,default:24,presets:`HOURS_PRESETS`,suffix:`hr`}]},R={market:`Market`,fundamentals:`Fundamentals`,options:`Options`,portfolio:`Portfolio`,technical:`Technical`,sentiment:`Sentiment`,macro:`Macro`,interaction:`Interaction`};function ye(e){return ve[e]??null}var be={comprehensive_analysis:{headline:`Comprehensive analysis`,description:`Run market, fundamentals, technical, sentiment, and macro analysts on one ticker, then synthesize.`,fields:[{name:`symbol`,kind:`symbol`,label:`Symbol`,required:!0,default:`NVDA`},{name:`depth`,kind:`segmented`,label:`Depth`,default:`standard`,options:[{value:`fast`,label:`Fast`},{value:`standard`,label:`Standard`},{value:`deep`,label:`Deep`}],helper:`Fast: market + fundamentals only. Deep: includes options + macro.`}],buildPrompt:e=>{let t=e.depth&&e.depth!==`standard`?` (${e.depth} depth)`:``;return`/analyze ${e.symbol}${t}`}},portfolio_builder:{headline:`Portfolio builder`,description:`Build a draft portfolio from goals and constraints. The agent will fetch candidates, check correlation, and present an allocation table.`,fields:[{name:`objective`,kind:`freetext`,label:`Objective`,required:!0,placeholder:`Long-term growth with US tech exposure`,maxLength:200,helper:`One or two sentences describing what the portfolio is for.`},{name:`budget`,kind:`money`,label:`Budget`,default:1e5,helper:`Total amount to allocate.`},{name:`riskProfile`,kind:`segmented`,label:`Risk profile`,default:`balanced`,options:[{value:`conservative`,label:`Conservative`},{value:`balanced`,label:`Balanced`},{value:`aggressive`,label:`Aggressive`}]},{name:`timeHorizon`,kind:`segmented`,label:`Time horizon`,default:`5y`,options:[{value:`1y`,label:`1Y`},{value:`3y`,label:`3Y`},{value:`5y`,label:`5Y`},{value:`10y`,label:`10Y+`}]},{name:`assetScope`,kind:`segmented`,label:`Asset scope`,default:`stocks`,options:[{value:`stocks`,label:`Stocks`},{value:`stocks_etfs`,label:`Stocks + ETFs`},{value:`stocks_crypto`,label:`Stocks + Crypto`}]},{name:`positionCount`,kind:`number-chips`,label:`Positions`,default:8,presets:[{value:5,label:`5`},{value:8,label:`8`},{value:12,label:`12`},{value:20,label:`20`}]},{name:`maxSinglePositionPct`,kind:`percent`,label:`Max single position`,default:.15,helper:`Concentration cap, e.g. 15%.`},{name:`excludeSectors`,kind:`multi-chips`,label:`Exclude sectors`,advanced:!0,options:[{value:`energy`,label:`Energy`},{value:`financials`,label:`Financials`},{value:`consumer_discretionary`,label:`Consumer Discr.`},{value:`healthcare`,label:`Healthcare`},{value:`tech`,label:`Technology`},{value:`real_estate`,label:`Real Estate`},{value:`utilities`,label:`Utilities`}]},{name:`incomeVsGrowth`,kind:`segmented`,label:`Tilt`,advanced:!0,options:[{value:`income`,label:`Income`},{value:`balanced`,label:`Balanced`},{value:`growth`,label:`Growth`}]}],buildPrompt:e=>{let t=[`${z(e.budget)} budget`,e.riskProfile&&`${e.riskProfile} risk`,e.timeHorizon&&`${e.timeHorizon} horizon`,e.assetScope&&xe(e.assetScope),e.positionCount&&`${e.positionCount} positions`,e.maxSinglePositionPct!=null&&`max ${(e.maxSinglePositionPct*100).toFixed(0)}% per position`,e.incomeVsGrowth&&`${e.incomeVsGrowth} tilt`,e.excludeSectors?.length&&`exclude ${e.excludeSectors.join(`, `)}`].filter(Boolean).join(`, `);return`Build me a portfolio for ${String(e.objective||``).trim()}. Constraints: ${t}.`}},options_screener:{headline:`Options screener`,description:`Pick contracts from a single ticker's chain that match your direction, DTE, and liquidity preferences.`,fields:[{name:`symbol`,kind:`symbol`,label:`Underlying`,required:!0,default:`NVDA`},{name:`direction`,kind:`segmented`,label:`Direction`,required:!0,default:`bullish`,options:[{value:`bullish`,label:`Bullish (calls)`},{value:`bearish`,label:`Bearish (puts)`}]},{name:`dteTarget`,kind:`segmented`,label:`Days to expiry`,required:!0,default:`30-45`,options:[{value:`0-7`,label:`0–7`},{value:`14-30`,label:`14–30`},{value:`30-45`,label:`30–45`},{value:`45-90`,label:`45–90`},{value:`90+`,label:`90+`}]},{name:`moneynessPreference`,kind:`segmented`,label:`Moneyness`,required:!0,default:`atm`,options:[{value:`itm`,label:`ITM`},{value:`atm`,label:`ATM`},{value:`otm`,label:`OTM`}]},{name:`liquidityMinimum`,kind:`segmented`,label:`Liquidity floor`,required:!0,default:`tight_spreads`,options:[{value:`any`,label:`Any`},{value:`tight_spreads`,label:`Tight spreads`},{value:`high_oi`,label:`High open interest`}]},{name:`objective`,kind:`select`,label:`Objective`,required:!0,default:`directional_leverage`,options:[{value:`directional_leverage`,label:`Directional leverage`},{value:`hedge`,label:`Hedge existing position`},{value:`income`,label:`Income (sell premium)`},{value:`speculative`,label:`Speculative (cheap convexity)`}]},{name:`maxPremium`,kind:`money`,label:`Max premium per contract`,advanced:!0},{name:`ivPreference`,kind:`segmented`,label:`IV preference`,advanced:!0,options:[{value:`any`,label:`Any`},{value:`low`,label:`Low IV`},{value:`high`,label:`High IV`}]}],buildPrompt:e=>{let t=[e.dteTarget&&`DTE ${e.dteTarget}`,e.moneynessPreference&&`${e.moneynessPreference.toUpperCase()} strikes`,e.liquidityMinimum&&Se(e.liquidityMinimum),e.objective&&Ce(e.objective),e.maxPremium!=null&&`max premium ${z(e.maxPremium)}`,e.ivPreference&&e.ivPreference!==`any`&&`${e.ivPreference} IV`].filter(Boolean).join(`, `);return`Screen options for ${e.symbol} (${e.direction||`bullish`}). ${t?`Filters: ${t}.`:``}`.trim()}},compare_assets:{headline:`Compare assets`,description:`Side-by-side comparison of two or more tickers across price, technicals, fundamentals, and risk.`,fields:[{name:`symbols`,kind:`symbols`,label:`Tickers`,required:!0,min:2,max:6,default:[`NVDA`,`AMD`],helper:`2 to 6 symbols.`},{name:`metrics`,kind:`multi-chips`,label:`Focus on`,advanced:!0,options:[{value:`valuation`,label:`Valuation`},{value:`growth`,label:`Growth`},{value:`profitability`,label:`Profitability`},{value:`momentum`,label:`Momentum`},{value:`risk`,label:`Risk`}]}],buildPrompt:e=>`Compare ${(e.symbols||[]).join(` vs `)} side by side.${e.metrics?.length?` Focus on ${e.metrics.join(`, `)}.`:``}`}};function xe(e){return e===`stocks_etfs`?`stocks and ETFs`:e===`stocks_crypto`?`stocks and crypto`:`stocks only`}function Se(e){return e===`tight_spreads`?`tight bid-ask spreads`:e===`high_oi`?`high open interest`:`any liquidity`}function Ce(e){return e===`directional_leverage`?`directional leverage`:e===`hedge`?`hedge an existing position`:e===`income`?`income via short premium`:e===`speculative`?`speculative cheap convexity`:e}function z(e){if(e==null)return``;let t=Number(e);return Number.isFinite(t)?`$${t.toLocaleString(`en-US`)}`:String(e)}function we(e){return be[e]??null}var Te=[{id:`workflows`,label:`Workflows`,icon:C},{id:`tools`,label:`Tools`,icon:m},{id:`providers`,label:`Providers`,icon:r}],Ee=`workflows`;function De({open:e,initialTab:t,catalog:n,onClose:r,send:i,setToast:a,startChatRun:o,fillComposer:s}){let c=t??Ee,l=e?`open:${c}`:`closed`,[d,f]=(0,T.useState)(l),[p,m]=(0,T.useState)(c),[g,_]=(0,T.useState)(``),[v,y]=(0,T.useState)(null),b=(0,T.useRef)(null);d!==l&&(f(l),e&&(m(c),_(``),y(null))),(0,T.useEffect)(()=>{b.current&&(b.current.scrollTop=0)},[v,p]);let x=(0,T.useCallback)(()=>{y(null),_(``),r()},[r]);return(0,k.jsx)(h,{open:e,onOpenChange:e=>{e||x()},children:(0,k.jsx)(u,{width:`xl`,handleLabel:`Catalog`,className:`bg-card p-0`,children:(0,k.jsxs)(`div`,{className:`grid min-h-0 flex-1 grid-rows-[auto_minmax(0,1fr)]`,children:[v?(0,k.jsx)(Pe,{selection:v,catalog:n,onBack:()=>y(null)}):(0,k.jsx)(Oe,{tab:p,setTab:m,query:g,setQuery:_,counts:{workflows:n?.workflows?.length??0,tools:n?.tools?.length??0,providers:n?.providers?.length??0}}),(0,k.jsx)(`div`,{ref:b,className:`min-h-0 overflow-y-auto overscroll-contain`,children:v?(0,k.jsx)(Fe,{selection:v,catalog:n,send:i,setToast:a,startChatRun:o,fillComposer:s,onClose:x,lookupSymbol:void 0}):(0,k.jsx)(Ae,{tab:p,query:g,catalog:n,onSelect:e=>y(e)})})]})})})}function Oe({tab:e,setTab:r,query:i,setQuery:o,counts:s}){return(0,k.jsxs)(`div`,{className:`border-b border-border`,children:[(0,k.jsx)(`div`,{className:`px-3 pt-2 sm:px-4`,children:(0,k.jsx)(`div`,{className:`flex w-full items-center gap-0.5 rounded-md bg-secondary p-0.5`,children:Te.map(t=>{let n=t.icon,i=e===t.id;return(0,k.jsxs)(`button`,{type:`button`,onClick:()=>r(t.id),"aria-pressed":i,className:a(`inline-flex h-8 min-w-0 flex-1 items-center justify-center gap-1.5 rounded-[5px] px-2 text-xs font-medium transition-colors`,i?`bg-card text-foreground shadow-subtle-xs`:`text-muted-foreground hover:text-foreground`),children:[(0,k.jsx)(n,{className:`hidden h-3.5 w-3.5 sm:inline`,"aria-hidden":`true`}),(0,k.jsx)(`span`,{className:`truncate`,children:t.label}),(0,k.jsx)(`span`,{className:a(`hidden rounded-full px-1.5 text-[10px] tabular-nums sm:inline`,i?`bg-secondary text-muted-foreground`:`text-muted-foreground/70`),children:s[t.id]??0})]},t.id)})})}),(0,k.jsxs)(`div`,{className:`flex items-center gap-2 px-3 py-2 sm:px-4`,children:[(0,k.jsx)(n,{"aria-hidden":`true`,className:`h-4 w-4 shrink-0 text-muted-foreground`}),(0,k.jsx)(p,{variant:`ghost`,value:i,onChange:e=>o(e.target.value),placeholder:ke(e),autoFocus:!0,className:`h-8 px-0 text-sm shadow-none`}),i?(0,k.jsx)(t,{variant:`ghost`,size:`icon-xs`,"aria-label":`Clear search`,onClick:()=>o(``),children:(0,k.jsx)(d,{})}):null]})]})}function ke(e){return e===`workflows`?`Search workflows`:e===`providers`?`Search providers`:`Search tools by name, label, or domain`}function Ae({tab:e,query:t,catalog:n,onSelect:r}){if(e===`workflows`){let e=Xe(n?.workflows??[],t);return e.length===0?(0,k.jsx)(B,{query:t,kind:`workflows`}):(0,k.jsx)(`ul`,{className:`grid divide-y divide-border`,children:e.map(e=>(0,k.jsx)(je,{workflow:e,onSelect:r},e.id))})}if(e===`providers`){let e=W(n?.providers??[],t);return e.length===0?(0,k.jsx)(B,{query:t,kind:`providers`}):(0,k.jsx)(`ul`,{className:`grid divide-y divide-border`,children:e.map(e=>(0,k.jsx)(Ne,{provider:e,onSelect:r},e.id))})}let i=Ye(n?.tools??[],t);if(i.length===0)return(0,k.jsx)(B,{query:t,kind:`tools`});let o=Ze(i,e=>e.domain??`tool`),s=[`market`,`fundamentals`,`options`,`portfolio`,`technical`,`sentiment`,`macro`,`interaction`];return(0,k.jsx)(`div`,{className:`grid`,children:[...o.keys()].sort((e,t)=>{let n=s.indexOf(e),r=s.indexOf(t);return(n===-1?999:n)-(r===-1?999:r)}).map((e,t)=>(0,k.jsxs)(`section`,{className:a(t===0?``:`mt-2`),children:[(0,k.jsx)(`h4`,{className:`px-4 pb-1 pt-3 text-[11px] font-medium uppercase tracking-[0.08em] text-muted-foreground`,children:R[e]??e}),(0,k.jsx)(`ul`,{className:`grid divide-y divide-border border-y border-border`,children:o.get(e).map(e=>(0,k.jsx)(Me,{tool:e,onSelect:r},e.name))})]},e))})}function je({workflow:e,onSelect:t}){return(0,k.jsx)(`li`,{children:(0,k.jsxs)(`button`,{type:`button`,onClick:()=>t({kind:`workflow`,id:e.id}),className:`group flex w-full items-start gap-3 px-4 py-3 text-left transition-colors hover:bg-secondary`,children:[(0,k.jsx)(C,{"aria-hidden":`true`,className:`mt-0.5 h-4 w-4 shrink-0 text-foreground`}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsx)(`div`,{className:`flex items-center gap-2`,children:(0,k.jsx)(`span`,{className:`text-sm font-semibold text-foreground`,children:e.name})}),(0,k.jsx)(`p`,{className:`mt-0.5 line-clamp-2 text-xs text-muted-foreground`,children:e.description})]}),(0,k.jsx)(y,{"aria-hidden":`true`,className:`mt-1 h-4 w-4 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100`})]})})}function Me({tool:e,onSelect:t}){let n=e.enabled===!1;return(0,k.jsx)(`li`,{children:(0,k.jsxs)(`button`,{type:`button`,onClick:()=>t({kind:`tool`,id:e.name}),className:a(`group flex w-full items-start gap-3 px-4 py-2.5 text-left transition-colors hover:bg-secondary`,n&&`opacity-60`),children:[(0,k.jsx)(m,{"aria-hidden":`true`,className:`mt-0.5 h-3.5 w-3.5 shrink-0 text-muted-foreground`}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(`span`,{className:`text-sm font-medium text-foreground`,children:e.label||U(e.name)}),(0,k.jsx)(`code`,{className:`hidden truncate text-[11px] tabular-nums text-muted-foreground/70 sm:inline`,children:e.name}),n?(0,k.jsx)(s,{variant:`outline`,className:`h-5 px-1.5 text-[10px]`,children:`disabled`}):null]}),(0,k.jsx)(`p`,{className:`mt-0.5 line-clamp-1 text-xs text-muted-foreground`,children:e.description})]}),(0,k.jsx)(y,{"aria-hidden":`true`,className:`mt-1 h-4 w-4 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100`})]})})}function Ne({provider:e,onSelect:t}){let n=G(e);return(0,k.jsx)(`li`,{children:(0,k.jsxs)(`button`,{type:`button`,onClick:()=>t({kind:`provider`,id:e.id}),className:`group flex w-full items-start gap-3 px-4 py-3 text-left transition-colors hover:bg-secondary`,children:[(0,k.jsx)(K(e),{"aria-hidden":`true`,className:`mt-0.5 h-4 w-4 shrink-0 text-muted-foreground`}),(0,k.jsxs)(`div`,{className:`min-w-0 flex-1`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(`span`,{className:`text-sm font-medium text-foreground`,children:e.displayName}),(0,k.jsx)(q,{status:n}),(0,k.jsx)(`span`,{className:a(`text-[11px]`,Y(n)),children:J(n)})]}),(0,k.jsx)(`p`,{className:`mt-0.5 line-clamp-2 text-xs text-muted-foreground`,children:(e.unlocks||[]).join(` · `)})]}),(0,k.jsx)(y,{"aria-hidden":`true`,className:`mt-1 h-4 w-4 shrink-0 text-muted-foreground opacity-0 transition-opacity group-hover:opacity-100`})]})})}function B({query:e,kind:t}){return(0,k.jsxs)(`div`,{className:`grid gap-2 p-12 text-center`,children:[(0,k.jsx)(n,{className:`mx-auto h-5 w-5 text-muted-foreground`,"aria-hidden":`true`}),(0,k.jsx)(`p`,{className:`text-sm font-medium text-foreground`,children:e?`No ${t} match "${e}"`:`No ${t} available`}),(0,k.jsx)(`p`,{className:`mx-auto max-w-xs text-xs text-muted-foreground`,children:e?`Try a shorter query or check spelling.`:`OpenCandle did not return entries for this section.`})]})}function Pe({selection:e,catalog:n,onBack:i}){let a=H(e,n),o=e.kind===`provider`&&a?K(a):r;return(0,k.jsxs)(`div`,{className:`flex items-center gap-2 border-b border-border px-3 py-2 sm:px-4`,children:[(0,k.jsx)(t,{variant:`ghost`,size:`icon-sm`,"aria-label":`Back to catalog`,onClick:i,children:(0,k.jsx)(b,{})}),(0,k.jsxs)(`div`,{className:`flex min-w-0 flex-1 items-center gap-2`,children:[e.kind===`workflow`?(0,k.jsx)(C,{className:`h-4 w-4 text-foreground`,"aria-hidden":`true`}):null,e.kind===`tool`?(0,k.jsx)(m,{className:`h-4 w-4 text-muted-foreground`,"aria-hidden":`true`}):null,e.kind===`provider`?(0,k.jsx)(o,{className:`h-4 w-4 text-muted-foreground`,"aria-hidden":`true`}):null,(0,k.jsx)(`h2`,{className:`truncate text-sm font-semibold text-foreground`,children:He(e,a)}),e.kind===`tool`&&a?.domain?(0,k.jsx)(s,{variant:`outline`,className:`hidden h-5 px-1.5 text-[10px] sm:inline-flex`,children:R[a.domain]??a.domain}):null]})]})}function Fe({selection:e,catalog:t,send:n,setToast:r,startChatRun:i,fillComposer:a,onClose:o,lookupSymbol:s}){let c=H(e,t);return c?e.kind===`workflow`?(0,k.jsx)(Ie,{workflow:c,startChatRun:i,fillComposer:a,onClose:o,setToast:r,lookupSymbol:s}):e.kind===`tool`?(0,k.jsx)(Le,{tool:c,send:n,startChatRun:i,fillComposer:a,onClose:o,setToast:r,lookupSymbol:s}):(0,k.jsx)(Re,{provider:c,send:n,setToast:r}):(0,k.jsxs)(`div`,{className:`grid gap-2 p-12 text-center`,children:[(0,k.jsx)(`p`,{className:`text-sm font-medium text-foreground`,children:`Selection no longer available`}),(0,k.jsx)(`p`,{className:`text-xs text-muted-foreground`,children:`The catalog refreshed while you were viewing this entry.`})]})}function Ie({workflow:e,startChatRun:n,fillComposer:r,onClose:i,setToast:o,lookupSymbol:s}){let c=we(e.id),l=c?.fields??[],[u,d]=(0,T.useState)(()=>P(l)),[f,p]=(0,T.useState)(!1),m=(0,T.useCallback)((e,t)=>d(n=>({...n,[e]:t})),[]),h=F(l,u),g=(0,T.useMemo)(()=>c?Je(c,u):e.prompt||e.name,[c,u,e]),_=l.filter(e=>!e.advanced),v=l.filter(e=>e.advanced);if(!c)return(0,k.jsxs)(`div`,{className:`p-6`,children:[(0,k.jsxs)(`p`,{className:`text-sm text-muted-foreground`,children:[`No builder defined for "`,e.name,`". The agent will use its default planner.`]}),(0,k.jsx)(`div`,{className:`mt-4 flex gap-2`,children:(0,k.jsx)(t,{variant:`brand`,onClick:()=>{n(e.prompt||e.name),i()},children:`Run with defaults`})})]});let b=e=>{if(h.length>0){o?.(h[0]);return}if(e===`send`){n(g),i();return}r?.(g),o?.(`Draft loaded — edit and send when ready.`),i()};return(0,k.jsxs)(`div`,{className:`grid animate-fade-in-once gap-5 px-4 py-4 sm:px-5`,children:[(0,k.jsx)(`p`,{className:`text-sm leading-5 text-muted-foreground`,children:c.description}),(0,k.jsx)(`div`,{className:`grid gap-3.5`,children:_.map(e=>(0,k.jsx)(N,{field:e,value:u[e.name],onChange:m,lookupSymbol:s},e.name))}),v.length>0?(0,k.jsxs)(`div`,{className:`grid gap-3.5 border-t border-border pt-4`,children:[(0,k.jsxs)(`button`,{type:`button`,onClick:()=>p(e=>!e),className:`inline-flex w-fit items-center gap-1.5 text-[11px] font-medium uppercase tracking-wider text-muted-foreground hover:text-foreground`,children:[(0,k.jsxs)(`span`,{children:[f?`Hide`:`Show`,` advanced`]}),(0,k.jsx)(y,{"aria-hidden":`true`,className:a(`h-3 w-3 transition-transform`,f&&`rotate-90`)})]}),f?v.map(e=>(0,k.jsx)(N,{field:e,value:u[e.name],onChange:m,lookupSymbol:s},e.name)):null]}):null,(0,k.jsx)(V,{prompt:g}),(0,k.jsxs)(`div`,{className:`sticky bottom-0 -mx-4 flex flex-wrap items-center justify-end gap-2 border-t border-border bg-card px-4 py-3 sm:-mx-5 sm:px-5`,children:[(0,k.jsx)(t,{variant:`bordered`,onClick:()=>b(`draft`),disabled:!g,children:`Edit in chat`}),(0,k.jsx)(t,{variant:`brand`,onClick:()=>b(`send`),disabled:!g,prefixIcon:S,children:`Run workflow`})]})]})}function Le({tool:e,send:n,startChatRun:r,fillComposer:i,onClose:a,setToast:o,lookupSymbol:s}){let c=(0,T.useMemo)(()=>ye(e.name)??Ue(e),[e]),[l,u]=(0,T.useState)(()=>P(c)),d=(0,T.useCallback)((e,t)=>u(n=>({...n,[e]:t})),[]),f=F(c,l),p=(0,T.useMemo)(()=>Ge(l),[l]),m=(0,T.useMemo)(()=>`Use ${e.name}${Ke(p)}`,[e,p]),h=t=>{if(f.length>0){o?.(f[0]);return}if(t===`send`){r(m),a();return}if(t===`draft`){i?.(m),o?.(`Draft loaded — edit and send when ready.`),a();return}t===`run`&&n?.(`tool.invoke`,{toolName:e.name,args:p})&&(o?.(`Running ${e.label||e.name}…`),a())};return(0,k.jsxs)(`div`,{className:`grid animate-fade-in-once gap-5 px-4 py-4 sm:px-5`,children:[(0,k.jsx)(`p`,{className:`text-sm leading-5 text-muted-foreground`,children:e.description}),c.length===0?(0,k.jsx)(`div`,{className:`rounded-md border border-dashed border-border bg-secondary px-3 py-2.5 text-xs text-muted-foreground`,children:`This tool takes no inputs.`}):(0,k.jsx)(`div`,{className:`grid gap-3.5`,children:c.map(e=>(0,k.jsx)(N,{field:e,value:l[e.name],onChange:d,lookupSymbol:s},e.name))}),(0,k.jsx)(V,{prompt:m,title:`Chat preview`}),(0,k.jsxs)(`div`,{className:`sticky bottom-0 -mx-4 flex flex-wrap items-center justify-end gap-2 border-t border-border bg-card px-4 py-3 sm:-mx-5 sm:px-5`,children:[(0,k.jsx)(t,{variant:`bordered`,size:`sm`,onClick:()=>h(`draft`),children:`Edit in chat`}),(0,k.jsx)(t,{variant:`brand`,size:`sm`,prefixIcon:S,onClick:()=>h(`run`),children:`Run now`})]})]})}function Re({provider:e,send:t,setToast:n}){return e.kind===`external-tool`?(0,k.jsx)(Be,{provider:e,send:t,setToast:n}):e.kind===`public-http`?(0,k.jsx)(Ve,{provider:e,send:t,setToast:n}):(0,k.jsx)(ze,{provider:e,send:t,setToast:n})}function ze({provider:e,send:n,setToast:r}){let o=`${e.id}:${e.apiKey||``}`,[s,c]=(0,T.useState)(o),[l,u]=(0,T.useState)(e.apiKey||``),[d,f]=(0,T.useState)(!1),m=G(e),h=m===`env`,g=l.trim(),_=!h&&g.length>0;s!==o&&(c(o),u(e.apiKey||``),f(!1));let v=()=>{if(h){r?.(`${e.displayName} is set via ${e.envVar}. Unset it to override here.`);return}g&&(r?.(`Verifying ${e.displayName} key…`),n?.(`provider.save_api_key`,{providerId:e.id,apiKey:g})&&u(``))};return(0,k.jsxs)(`div`,{className:`grid animate-fade-in-once gap-5 px-4 py-4 sm:px-5`,children:[(0,k.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,k.jsxs)(`div`,{className:`flex items-center gap-2`,children:[(0,k.jsx)(q,{status:m}),(0,k.jsx)(`span`,{className:a(`text-xs font-medium`,Y(m)),children:J(m)}),h?(0,k.jsxs)(`code`,{className:`text-[11px] text-muted-foreground`,children:[`env: `,e.envVar]}):null]}),(0,k.jsx)(`p`,{className:`text-sm leading-5 text-muted-foreground`,children:e.fallbackDescription?(0,k.jsxs)(k.Fragment,{children:[`If absent: `,e.fallbackDescription,`.`]}):(0,k.jsxs)(k.Fragment,{children:[`Required for: `,(e.unlocks||[]).join(`, `)||`this provider's tools`,`.`]})})]}),(0,k.jsxs)(`div`,{className:`grid gap-2`,children:[(0,k.jsx)(`span`,{className:`text-[11px] font-medium uppercase tracking-wider text-muted-foreground`,children:`Unlocks`}),(0,k.jsx)(`ul`,{className:`grid gap-1`,children:(e.unlocks||[]).map(e=>(0,k.jsxs)(`li`,{className:`flex items-baseline gap-2 text-sm text-foreground`,children:[(0,k.jsx)(`span`,{"aria-hidden":`true`,className:`mt-1 h-1 w-1 rounded-full bg-foreground/40`}),(0,k.jsx)(`span`,{children:e})]},e))})]}),(0,k.jsxs)(`div`,{className:`grid gap-2`,children:[(0,k.jsx)(`label`,{htmlFor:`provider-api-key-${e.id}`,className:`text-xs font-medium text-foreground`,children:`API key`}),(0,k.jsxs)(`div`,{className:`relative`,children:[(0,k.jsx)(p,{id:`provider-api-key-${e.id}`,type:d?`text`:`password`,value:l,onChange:e=>u(e.target.value),placeholder:`Paste your ${e.displayName} key`,disabled:h,className:`pr-10 font-mono`,autoCapitalize:`none`,autoComplete:`off`,spellCheck:!1,onKeyDown:e=>{e.key===`Enter`&&_&&(e.preventDefault(),v())}}),(0,k.jsx)(t,{type:`button`,variant:`ghost`,size:`icon-xs`,className:`absolute right-1 top-1/2 -translate-y-1/2`,"aria-label":d?`Hide API key`:`Show API key`,tooltip:d?`Hide API key`:`Show API key`,onClick:()=>f(e=>!e),disabled:!l,children:d?(0,k.jsx)(te,{}):(0,k.jsx)(ne,{})})]}),(0,k.jsx)(`p`,{className:`text-[11px] leading-4 text-muted-foreground`,children:h?`Currently set via ${e.envVar}. Unset that variable to manage the key here.`:m===`file`?`Saved to ~/.opencandle/config.json. Paste a new key to replace.`:e.instructionsHint||`Saved to ~/.opencandle/config.json.`})]}),(0,k.jsxs)(`div`,{className:`sticky bottom-0 -mx-4 flex flex-wrap items-center justify-end gap-2 border-t border-border bg-card px-4 py-3 sm:-mx-5 sm:px-5`,children:[e.signupUrl?(0,k.jsx)(t,{variant:`ghost`,size:`sm`,suffixIcon:i,onClick:()=>window.open(e.signupUrl,`_blank`,`noreferrer`),children:`Get a key`}):null,(0,k.jsx)(t,{variant:`brand`,size:`sm`,onClick:v,disabled:!_,children:m===`file`?`Replace key`:`Save key`})]})]})}function Be({provider:e,send:n,setToast:r}){let i=G(e),o=e.statusDetail,s=i===`skipped`;return(0,k.jsxs)(`div`,{className:`grid animate-fade-in-once gap-5 px-4 py-4 sm:px-5`,children:[(0,k.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,k.jsx)(q,{status:i}),(0,k.jsx)(`span`,{className:a(`text-xs font-medium`,Y(i)),children:J(i)}),o?.checkedAt?(0,k.jsxs)(`span`,{className:`text-[11px] text-muted-foreground`,children:[`Checked `,$(o.checkedAt)]}):null]}),(0,k.jsx)(`p`,{className:`text-sm leading-5 text-muted-foreground`,children:e.fallbackDescription})]}),(0,k.jsxs)(`div`,{className:`grid gap-2`,children:[(0,k.jsx)(`span`,{className:`text-[11px] font-medium uppercase tracking-wider text-muted-foreground`,children:`Install`}),(0,k.jsxs)(`div`,{className:`flex min-w-0 items-center gap-2 rounded-md border border-border bg-secondary px-3 py-2`,children:[(0,k.jsx)(w,{className:`h-3.5 w-3.5 shrink-0 text-muted-foreground`,"aria-hidden":`true`}),(0,k.jsx)(`code`,{className:`min-w-0 flex-1 overflow-x-auto whitespace-nowrap text-[11px] text-foreground`,children:e.installCmd}),(0,k.jsx)(t,{type:`button`,variant:`ghost`,size:`icon-xs`,"aria-label":`Copy install command`,tooltip:`Copy install command`,onClick:()=>{navigator.clipboard?.writeText?.(e.installCmd),r?.(`Install command copied.`)},children:(0,k.jsx)(x,{})})]})]}),(0,k.jsxs)(`div`,{className:`grid gap-2`,children:[(0,k.jsx)(`span`,{className:`text-[11px] font-medium uppercase tracking-wider text-muted-foreground`,children:`Session source`}),(0,k.jsxs)(`p`,{className:`text-sm leading-5 text-muted-foreground`,children:[`Uses your normal browser session. Supported browsers:`,` `,(e.supportedBrowsers||[]).join(`, `)||`Chrome, Arc, Edge, Firefox, Brave`,`.`]}),o?.message?(0,k.jsx)(`p`,{className:`rounded-md border border-border bg-secondary px-3 py-2 text-xs leading-5 text-muted-foreground`,children:o.message}):null]}),(0,k.jsxs)(`div`,{className:`sticky bottom-0 -mx-4 flex flex-wrap items-center justify-end gap-2 border-t border-border bg-card px-4 py-3 sm:-mx-5 sm:px-5`,children:[(0,k.jsx)(t,{variant:`bordered`,size:`sm`,prefixIcon:c,onClick:()=>{r?.(s?`Re-enabling ${e.displayName} and checking install status...`:`Checking ${e.displayName} install status...`),n?.(`provider.status.check`,{providerId:e.id,mode:`install`,reenable:s})},children:s?`Re-enable & check install`:`Check install`}),(0,k.jsx)(t,{variant:`brand`,size:`sm`,onClick:()=>{r?.(s?`Re-enabling ${e.displayName} and checking session. This may read browser cookies and trigger a Keychain prompt.`:`Checking ${e.displayName} session. This may read browser cookies and trigger a Keychain prompt.`),n?.(`provider.status.check`,{providerId:e.id,mode:`session`,reenable:s})},children:s?`Re-enable & check session`:`Check session`})]})]})}function Ve({provider:e,send:n,setToast:r}){let i=G(e),o=e.statusDetail;return(0,k.jsxs)(`div`,{className:`grid animate-fade-in-once gap-5 px-4 py-4 sm:px-5`,children:[(0,k.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,k.jsxs)(`div`,{className:`flex flex-wrap items-center gap-2`,children:[(0,k.jsx)(q,{status:i}),(0,k.jsx)(`span`,{className:a(`text-xs font-medium`,Y(i)),children:J(i)}),o?.checkedAt?(0,k.jsxs)(`span`,{className:`text-[11px] text-muted-foreground`,children:[`Checked `,$(o.checkedAt)]}):null]}),(0,k.jsx)(`p`,{className:`text-sm leading-5 text-muted-foreground`,children:e.fallbackDescription||`No account or API key is required.`})]}),(0,k.jsxs)(`div`,{className:`grid gap-2`,children:[(0,k.jsx)(`span`,{className:`text-[11px] font-medium uppercase tracking-wider text-muted-foreground`,children:`Probe`}),(0,k.jsx)(`code`,{className:`overflow-x-auto rounded-md border border-border bg-secondary px-3 py-2 text-[11px] text-muted-foreground`,children:e.probeUrl}),o?.message?(0,k.jsx)(`p`,{className:`text-xs leading-5 text-muted-foreground`,children:o.message}):null]}),(0,k.jsx)(`div`,{className:`sticky bottom-0 -mx-4 flex flex-wrap items-center justify-end gap-2 border-t border-border bg-card px-4 py-3 sm:-mx-5 sm:px-5`,children:(0,k.jsx)(t,{variant:`brand`,size:`sm`,prefixIcon:c,onClick:()=>{r?.(`Checking ${e.displayName} reachability...`),n?.(`provider.status.check`,{providerId:e.id})},children:`Check reachability`})})]})}function V({prompt:e,title:t=`Chat prompt`}){return(0,k.jsxs)(`div`,{className:`grid gap-1.5`,children:[(0,k.jsx)(`span`,{className:`text-[11px] font-medium uppercase tracking-wider text-muted-foreground`,children:t}),(0,k.jsx)(`pre`,{className:`overflow-auto whitespace-pre-wrap rounded-md border border-border bg-secondary px-3 py-2 font-mono text-xs leading-5 text-foreground`,children:e||`Fill the required fields to preview the chat prompt.`})]})}function H(e,t){return!e||!t?null:e.kind===`workflow`?t.workflows?.find(t=>t.id===e.id)??null:e.kind===`tool`?t.tools?.find(t=>t.name===e.id)??null:e.kind===`provider`?t.providers?.find(t=>t.id===e.id)??null:null}function He(e,t){return t?e.kind===`workflow`?t.name:e.kind===`tool`?t.label||U(t.name):e.kind===`provider`?t.displayName:`Catalog`:`Catalog`}function U(e){return String(e||``).replace(/^get_/,``).replace(/_/g,` `)}function Ue(e){let t=e.parameters?.properties||{};return Object.entries(t).map(([t,n])=>{let r=String(n.description||``);return{name:t,kind:n.type===`number`?`text`:n.type===`boolean`?`select`:`text`,label:We(t),placeholder:n.examples?.[0],helper:r.length>80?`${r.slice(0,80)}…`:r,required:e.parameters?.required?.includes?.(t)??!1}})}function We(e){return e.replace(/_/g,` `).replace(/\b\w/g,e=>e.toUpperCase())}function Ge(e){let t={};for(let[n,r]of Object.entries(e))r===void 0||r===``||Array.isArray(r)&&r.length===0||(t[n]=r);return t}function Ke(e){let t=Object.entries(e);return t.length===0?``:` with ${t.map(([e,t])=>`${e}=${qe(t)}`).join(`, `)}`}function qe(e){return Array.isArray(e)?e.join(`,`):typeof e==`string`&&e.includes(` `)?JSON.stringify(e):String(e)}function Je(e,t){try{return e.buildPrompt(t)||``}catch{return``}}function Ye(e,t){if(!t.trim())return e;let n=t.toLowerCase();return e.filter(e=>[e.name,e.label,e.description,e.domain].some(e=>String(e||``).toLowerCase().includes(n)))}function Xe(e,t){if(!t.trim())return e;let n=t.toLowerCase();return e.filter(e=>[e.id,e.name,e.description].some(e=>String(e||``).toLowerCase().includes(n)))}function W(e,t){if(!t.trim())return e;let n=t.toLowerCase();return e.filter(e=>[e.id,e.kind,e.displayName,e.envVar,e.binary,e.installCmd,e.probeUrl,...e.aliases||[],...e.unlocks||[]].some(e=>String(e||``).toLowerCase().includes(n)))}function Ze(e,t){let n=new Map;for(let r of e){let e=t(r);n.has(e)||n.set(e,[]),n.get(e).push(r)}return n}function G(e){return e.statusDetail?.state??e.status??e.source??`absent`}function K(e){return e.kind===`external-tool`?w:e.kind===`public-http`?ee:r}function q({status:e}){return(0,k.jsx)(`span`,{"aria-hidden":`true`,className:a(`inline-block h-1.5 w-1.5 rounded-full`,X.has(e)?`bg-success`:Z.has(e)?`bg-info`:Q.has(e)?`bg-destructive`:`bg-warning`)})}function J(e){return e===`configured`||e===`file`?`Configured`:e===`env`?`From environment`:e===`installed`?`Installed`:e===`missing`?`Missing`:e===`session_ok`?`Session ready`:e===`session_missing`?`Login needed`:e===`session_stale`?`Session stale`:e===`skipped`?`Skipped`:e===`reachable`?`Reachable`:e===`unreachable`?`Unreachable`:e===`error`?`Needs attention`:e===`unknown`?`Not checked`:`Not configured`}function Y(e){return X.has(e)?`text-success`:Z.has(e)?`text-info`:Q.has(e)?`text-destructive`:`text-warning`}var X=new Set([`configured`,`file`,`installed`,`session_ok`,`reachable`]),Z=new Set([`env`,`skipped`]),Q=new Set([`error`,`unreachable`]);function $(e){let t=Date.parse(e);if(Number.isNaN(t))return`just now`;let n=Math.max(0,Math.round((Date.now()-t)/1e3));if(n<60)return`just now`;let r=Math.round(n/60);if(r<60)return`${r}m ago`;let i=Math.round(r/60);return i<24?`${i}h ago`:`${Math.round(i/24)}d ago`}export{De as CatalogOverlay};
|