@ebowwa/daemons 0.5.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.
Files changed (42) hide show
  1. package/README.md +264 -0
  2. package/dist/bin/discord-cli.js +124118 -0
  3. package/dist/bin/manager.js +143 -0
  4. package/dist/bin/telegram-cli.js +124114 -0
  5. package/dist/index.js +125340 -0
  6. package/package.json +94 -0
  7. package/src/agent.ts +111 -0
  8. package/src/channels/base.ts +573 -0
  9. package/src/channels/discord.ts +306 -0
  10. package/src/channels/index.ts +169 -0
  11. package/src/channels/telegram.ts +315 -0
  12. package/src/daemon.ts +534 -0
  13. package/src/hooks.ts +97 -0
  14. package/src/index.ts +111 -0
  15. package/src/memory.ts +369 -0
  16. package/src/skills/coding/commit.ts +202 -0
  17. package/src/skills/coding/execute-subtask.ts +136 -0
  18. package/src/skills/coding/fix-issues.ts +126 -0
  19. package/src/skills/coding/index.ts +26 -0
  20. package/src/skills/coding/plan-task.ts +158 -0
  21. package/src/skills/coding/quality-check.ts +155 -0
  22. package/src/skills/index.ts +65 -0
  23. package/src/skills/registry.ts +380 -0
  24. package/src/skills/shared/index.ts +21 -0
  25. package/src/skills/shared/reflect.ts +156 -0
  26. package/src/skills/shared/review.ts +201 -0
  27. package/src/skills/shared/trajectory.ts +319 -0
  28. package/src/skills/trading/analyze-market.ts +144 -0
  29. package/src/skills/trading/check-risk.ts +176 -0
  30. package/src/skills/trading/execute-trade.ts +185 -0
  31. package/src/skills/trading/generate-signal.ts +160 -0
  32. package/src/skills/trading/index.ts +26 -0
  33. package/src/skills/trading/monitor-position.ts +179 -0
  34. package/src/skills/types.ts +235 -0
  35. package/src/skills/workflows.ts +340 -0
  36. package/src/state.ts +77 -0
  37. package/src/tools.ts +134 -0
  38. package/src/types.ts +314 -0
  39. package/src/workflow.ts +341 -0
  40. package/src/workflows/coding.ts +580 -0
  41. package/src/workflows/index.ts +61 -0
  42. package/src/workflows/trading.ts +608 -0
@@ -0,0 +1,201 @@
1
+ /**
2
+ * GLM Daemon - Review Skill
3
+ *
4
+ * Quality review for code changes or trading performance.
5
+ * Used by coding and trading workflows.
6
+ */
7
+
8
+ import { z } from "zod";
9
+ import type { Skill, SkillContext, SkillResult } from "../types.js";
10
+ import { skillRegistry } from "../registry.js";
11
+
12
+ /**
13
+ * Review skill parameters
14
+ */
15
+ const ReviewParams = z.object({
16
+ /** Type of review: "code" | "trading" | "general" */
17
+ type: z.enum(["code", "trading", "general"]).optional(),
18
+ /** Specific criteria to review against */
19
+ criteria: z.array(z.string()).optional(),
20
+ /** Whether to approve on success */
21
+ approveOnPass: z.boolean().optional(),
22
+ });
23
+
24
+ /**
25
+ * Review result data
26
+ */
27
+ interface ReviewData {
28
+ /** Whether the review passed */
29
+ approved: boolean;
30
+ /** Issues found during review */
31
+ issues: string[];
32
+ /** Suggestions for improvement */
33
+ suggestions: string[];
34
+ /** Overall assessment */
35
+ assessment: string;
36
+ /** Score (0-100) if applicable */
37
+ score?: number;
38
+ }
39
+
40
+ /**
41
+ * Default review criteria by type
42
+ */
43
+ const DEFAULT_CRITERIA: Record<string, string[]> = {
44
+ code: [
45
+ "Correctness: Does it work as intended?",
46
+ "Edge cases: Are error cases handled?",
47
+ "Security: Any vulnerabilities?",
48
+ "Performance: Any bottlenecks?",
49
+ "Maintainability: Is it readable?",
50
+ ],
51
+ trading: [
52
+ "Risk management: Position size within limits?",
53
+ "Stop loss: Properly placed?",
54
+ "Entry/Exit: Logical levels?",
55
+ "Market conditions: Suitable for current state?",
56
+ "P&L projection: Realistic expectations?",
57
+ ],
58
+ general: [
59
+ "Completeness: Task fully addressed?",
60
+ "Quality: Meets standards?",
61
+ "Consistency: Follows patterns?",
62
+ ],
63
+ };
64
+
65
+ /**
66
+ * Review skill definition
67
+ */
68
+ export const reviewSkill: Skill<z.infer<typeof ReviewParams>, ReviewData> = {
69
+ id: "/review",
70
+ name: "Review",
71
+ description:
72
+ "Quality review for changes or decisions. Can review code, trades, or general work.",
73
+ paramsSchema: ReviewParams,
74
+ tags: ["shared", "quality", "validation"],
75
+ parallelizable: false,
76
+ produces: ["approved", "issues", "assessment"],
77
+
78
+ async execute(params, context): Promise<SkillResult<ReviewData>> {
79
+ const reviewType = params?.type || "general";
80
+ const criteria = params?.criteria || DEFAULT_CRITERIA[reviewType] || DEFAULT_CRITERIA.general;
81
+ const approveOnPass = params?.approveOnPass ?? true;
82
+
83
+ console.log(`[/review] Type: ${reviewType}`);
84
+ console.log(`[/review] Criteria: ${criteria.length} items`);
85
+
86
+ // Build review prompt based on type
87
+ let reviewContext = "";
88
+ switch (reviewType) {
89
+ case "code":
90
+ reviewContext = `
91
+ Files changed: ${context.state.filesChanged.join(", ") || "none"}
92
+ Subtasks completed: ${context.state.slam.completedSubtasks.length}/${context.state.slam.subtasks.length}
93
+ Task: ${context.state.prompt}
94
+ Completion promise: ${context.state.promise}
95
+ `;
96
+ break;
97
+ case "trading":
98
+ reviewContext = `
99
+ Current position: ${JSON.stringify(context.custom.position || "none")}
100
+ P&L: ${context.custom.currentPnL || "N/A"}
101
+ Risk level: ${context.custom.riskLevel || "unknown"}
102
+ Iteration: ${context.state.iteration}
103
+ `;
104
+ break;
105
+ default:
106
+ reviewContext = `
107
+ Task: ${context.state.prompt}
108
+ Files changed: ${context.state.filesChanged.join(", ") || "none"}
109
+ Iterations: ${context.state.iteration}
110
+ `;
111
+ }
112
+
113
+ const prompt = `Perform a thorough review.
114
+
115
+ Type: ${reviewType}
116
+
117
+ Context:
118
+ ${reviewContext}
119
+
120
+ Review Criteria:
121
+ ${criteria.map((c, i) => `${i + 1}. ${c}`).join("\n")}
122
+
123
+ For each criterion:
124
+ 1. Assess whether it's met
125
+ 2. Note any issues or concerns
126
+ 3. Provide suggestions if applicable
127
+
128
+ Respond in JSON format:
129
+ {
130
+ "approved": true|false,
131
+ "issues": ["list of issues found"],
132
+ "suggestions": ["list of improvement suggestions"],
133
+ "assessment": "overall assessment text",
134
+ "score": 0-100
135
+ }
136
+
137
+ If all criteria are met and there are no critical issues, set approved to true.
138
+ If there are critical issues that must be fixed, set approved to false.`;
139
+
140
+ try {
141
+ const response = await context.agent.execute(prompt);
142
+
143
+ // Parse JSON from response
144
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
145
+ let data: ReviewData;
146
+
147
+ if (jsonMatch) {
148
+ const parsed = JSON.parse(jsonMatch[0]);
149
+ data = {
150
+ approved: parsed.approved ?? false,
151
+ issues: parsed.issues || [],
152
+ suggestions: parsed.suggestions || [],
153
+ assessment: parsed.assessment || "",
154
+ score: parsed.score,
155
+ };
156
+ } else {
157
+ // Fallback: detect approval from response
158
+ const lowerResponse = response.toLowerCase();
159
+ const hasApproved = lowerResponse.includes("approved") && !lowerResponse.includes("not approved");
160
+ data = {
161
+ approved: approveOnPass && hasApproved,
162
+ issues: [],
163
+ suggestions: [],
164
+ assessment: response.substring(0, 500),
165
+ };
166
+ }
167
+
168
+ console.log(`[/review] Result: ${data.approved ? "APPROVED" : "NEEDS WORK"}`);
169
+ if (data.issues.length > 0) {
170
+ console.log(`[/review] Issues: ${data.issues.length}`);
171
+ }
172
+ if (data.score !== undefined) {
173
+ console.log(`[/review] Score: ${data.score}/100`);
174
+ }
175
+
176
+ return {
177
+ success: true,
178
+ data,
179
+ contextUpdates: {
180
+ approved: data.approved,
181
+ reviewIssues: data.issues,
182
+ reviewScore: data.score,
183
+ },
184
+ };
185
+ } catch (error) {
186
+ return {
187
+ success: false,
188
+ error: error instanceof Error ? error.message : String(error),
189
+ contextUpdates: {
190
+ approved: false,
191
+ },
192
+ };
193
+ }
194
+ },
195
+ };
196
+
197
+ // Auto-register
198
+ skillRegistry.register(reviewSkill);
199
+
200
+ export { ReviewParams };
201
+ export type { ReviewData };
@@ -0,0 +1,319 @@
1
+ /**
2
+ * GLM Daemon - Trajectory Skill
3
+ *
4
+ * Integration with @ebowwa/trajectory for learning from execution patterns.
5
+ * Provides:
6
+ * - Query learned patterns by domain
7
+ * - Record execution results for learning
8
+ * - Provide context about past successful patterns
9
+ */
10
+
11
+ import { z } from "zod";
12
+ import type { Skill, SkillContext, SkillResult } from "../types.js";
13
+ import { skillRegistry } from "../registry.js";
14
+
15
+ /**
16
+ * Trajectory skill parameters
17
+ */
18
+ const TrajectoryParams = z.discriminatedUnion("action", [
19
+ z.object({
20
+ /** Query patterns by domain */
21
+ action: z.literal("query"),
22
+ /** Domain to query (e.g., "math", "trading", "coding") */
23
+ domain: z.string(),
24
+ /** Minimum success rate filter (0-1) */
25
+ minSuccessRate: z.number().min(0).max(1).optional(),
26
+ /** Maximum patterns to return */
27
+ limit: z.number().min(1).max(50).optional(),
28
+ }),
29
+ z.object({
30
+ /** Record execution result */
31
+ action: z.literal("record"),
32
+ /** Execution data to record */
33
+ execution: z.object({
34
+ primitiveId: z.string(),
35
+ package: z.string(),
36
+ version: z.string(),
37
+ inputs: z.record(z.unknown()),
38
+ output: z.unknown(),
39
+ durationNs: z.number(),
40
+ verified: z.boolean(),
41
+ invariantsChecked: z.array(z.string()).optional(),
42
+ verificationErrors: z.array(z.string()).optional(),
43
+ specId: z.string().optional(),
44
+ sessionId: z.string().optional(),
45
+ }),
46
+ }),
47
+ z.object({
48
+ /** Get context about past patterns for a given task */
49
+ action: z.literal("context"),
50
+ /** Task description to find relevant patterns */
51
+ task: z.string(),
52
+ /** Domain hint */
53
+ domain: z.string().optional(),
54
+ }),
55
+ z.object({
56
+ /** Get memory statistics */
57
+ action: z.literal("stats"),
58
+ }),
59
+ ]);
60
+
61
+ /**
62
+ * Pattern info from trajectory memory
63
+ */
64
+ interface LearnedPattern {
65
+ primitiveSequence: string[];
66
+ avgDurationMs: number;
67
+ successRate: number;
68
+ }
69
+
70
+ /**
71
+ * Trajectory skill result data
72
+ */
73
+ interface TrajectoryData {
74
+ action: "query" | "record" | "context" | "stats";
75
+ patterns?: LearnedPattern[];
76
+ recorded?: {
77
+ executionId: string;
78
+ timestamp: number;
79
+ };
80
+ context?: {
81
+ relevantPatterns: LearnedPattern[];
82
+ suggestions: string[];
83
+ historicalSuccess: number;
84
+ };
85
+ stats?: {
86
+ totalExecutions: number;
87
+ totalCompositions: number;
88
+ totalTrajectories: number;
89
+ successfulTrajectories: number;
90
+ avgExecutionsPerComposition: number;
91
+ avgAttemptsPerTrajectory: number;
92
+ };
93
+ }
94
+
95
+ /**
96
+ * Lazy-loaded trajectory memory reference
97
+ * We import dynamically to avoid bundling issues if trajectory is not installed
98
+ */
99
+ let _trajectoryMemory: InstanceType<
100
+ typeof import("@ebowwa/trajectory").TrajectoryMemory
101
+ > | null = null;
102
+ let _trajectoryAvailable: boolean | null = null;
103
+
104
+ /**
105
+ * Get or initialize trajectory memory
106
+ */
107
+ async function getTrajectoryMemory(): Promise<
108
+ InstanceType<typeof import("@ebowwa/trajectory").TrajectoryMemory> | null
109
+ > {
110
+ if (_trajectoryAvailable === false) {
111
+ return null;
112
+ }
113
+
114
+ if (_trajectoryMemory) {
115
+ return _trajectoryMemory;
116
+ }
117
+
118
+ try {
119
+ const { TrajectoryMemory } = await import("@ebowwa/trajectory");
120
+
121
+ // Use default path or custom path from env
122
+ const dbPath = process.env.TRAJECTORY_DB_PATH || ".trajectory/memory.lmdb";
123
+ _trajectoryMemory = new TrajectoryMemory({ path: dbPath });
124
+ _trajectoryAvailable = true;
125
+ return _trajectoryMemory;
126
+ } catch (error) {
127
+ console.warn(
128
+ "[/trajectory] @ebowwa/trajectory not available or initialization failed:",
129
+ error instanceof Error ? error.message : String(error)
130
+ );
131
+ _trajectoryAvailable = false;
132
+ return null;
133
+ }
134
+ }
135
+
136
+ /**
137
+ * Trajectory skill definition
138
+ */
139
+ export const trajectorySkill: Skill<
140
+ z.infer<typeof TrajectoryParams>,
141
+ TrajectoryData
142
+ > = {
143
+ id: "/trajectory",
144
+ name: "Trajectory",
145
+ description:
146
+ "Query and record execution patterns for learning. Integrates with @ebowwa/trajectory memory system.",
147
+ paramsSchema: TrajectoryParams,
148
+ tags: ["shared", "learning", "memory", "meta"],
149
+ parallelizable: true,
150
+ maxRetries: 1,
151
+
152
+ async execute(params, context): Promise<SkillResult<TrajectoryData>> {
153
+ const memory = await getTrajectoryMemory();
154
+
155
+ if (!memory) {
156
+ return {
157
+ success: false,
158
+ error:
159
+ "Trajectory memory not available. Ensure @ebowwa/trajectory is installed.",
160
+ data: { action: params.action },
161
+ };
162
+ }
163
+
164
+ try {
165
+ switch (params.action) {
166
+ case "query": {
167
+ const { domain, minSuccessRate = 0.5, limit = 10 } = params;
168
+
169
+ console.log("[/trajectory] Querying patterns for domain:", domain);
170
+
171
+ let patterns = memory.findSuccessfulPatterns(domain);
172
+
173
+ // Filter by success rate
174
+ patterns = patterns.filter((p) => p.successRate >= minSuccessRate);
175
+
176
+ // Sort by success rate and limit
177
+ patterns = patterns
178
+ .sort((a, b) => b.successRate - a.successRate)
179
+ .slice(0, limit);
180
+
181
+ console.log("[/trajectory] Found", patterns.length, "patterns for", domain);
182
+
183
+ return {
184
+ success: true,
185
+ data: {
186
+ action: "query",
187
+ patterns,
188
+ },
189
+ };
190
+ }
191
+
192
+ case "record": {
193
+ const { execution } = params;
194
+
195
+ console.log("[/trajectory] Recording execution:", execution.primitiveId);
196
+
197
+ const record = memory.recordExecution({
198
+ primitive: {
199
+ id: execution.primitiveId,
200
+ package: execution.package,
201
+ version: execution.version,
202
+ },
203
+ inputs: execution.inputs,
204
+ output: execution.output,
205
+ durationNs: execution.durationNs,
206
+ verified: execution.verified,
207
+ invariantsChecked: execution.invariantsChecked || [],
208
+ verificationErrors: execution.verificationErrors || [],
209
+ specId: execution.specId,
210
+ sessionId: execution.sessionId,
211
+ });
212
+
213
+ console.log("[/trajectory] Recorded execution", record.id);
214
+
215
+ return {
216
+ success: true,
217
+ data: {
218
+ action: "record",
219
+ recorded: {
220
+ executionId: record.id,
221
+ timestamp: record.timestamp,
222
+ },
223
+ },
224
+ };
225
+ }
226
+
227
+ case "context": {
228
+ const { task, domain } = params;
229
+
230
+ console.log("[/trajectory] Getting context for task:", task.substring(0, 50));
231
+
232
+ // Query patterns from relevant domains
233
+ const domains = domain
234
+ ? [domain]
235
+ : ["coding", "trading", "math", "general"];
236
+
237
+ let allPatterns: LearnedPattern[] = [];
238
+ for (const d of domains) {
239
+ const patterns = memory.findSuccessfulPatterns(d);
240
+ allPatterns.push(...patterns);
241
+ }
242
+
243
+ // Sort by success rate and get top patterns
244
+ const relevantPatterns = allPatterns
245
+ .sort((a, b) => b.successRate - a.successRate)
246
+ .slice(0, 5);
247
+
248
+ // Generate suggestions based on patterns
249
+ const suggestions: string[] = [];
250
+ if (relevantPatterns.length > 0) {
251
+ suggestions.push(
252
+ "Past successful patterns: " + relevantPatterns[0].primitiveSequence.join(" -> ")
253
+ );
254
+ if (relevantPatterns[0].successRate > 0.8) {
255
+ suggestions.push(
256
+ "This pattern has high success rate - consider following similar approach"
257
+ );
258
+ }
259
+ }
260
+
261
+ const stats = memory.getStats();
262
+ const historicalSuccess =
263
+ stats.totalTrajectories > 0
264
+ ? stats.successfulTrajectories / stats.totalTrajectories
265
+ : 0;
266
+
267
+ console.log("[/trajectory] Found", relevantPatterns.length, "relevant patterns");
268
+
269
+ return {
270
+ success: true,
271
+ data: {
272
+ action: "context",
273
+ context: {
274
+ relevantPatterns,
275
+ suggestions,
276
+ historicalSuccess,
277
+ },
278
+ },
279
+ };
280
+ }
281
+
282
+ case "stats": {
283
+ console.log("[/trajectory] Getting memory statistics");
284
+
285
+ const stats = memory.getStats();
286
+
287
+ console.log("[/trajectory] Stats:", stats.totalExecutions, "executions,", stats.successfulTrajectories + "/" + stats.totalTrajectories, "successful trajectories");
288
+
289
+ return {
290
+ success: true,
291
+ data: {
292
+ action: "stats",
293
+ stats,
294
+ },
295
+ };
296
+ }
297
+
298
+ default:
299
+ return {
300
+ success: false,
301
+ error: "Unknown action: " + (params as { action: string }).action,
302
+ data: { action: (params as { action: string }).action as TrajectoryData["action"] },
303
+ };
304
+ }
305
+ } catch (error) {
306
+ return {
307
+ success: false,
308
+ error: error instanceof Error ? error.message : String(error),
309
+ data: { action: params.action },
310
+ };
311
+ }
312
+ },
313
+ };
314
+
315
+ // Auto-register
316
+ skillRegistry.register(trajectorySkill);
317
+
318
+ export { TrajectoryParams };
319
+ export type { TrajectoryData, LearnedPattern };
@@ -0,0 +1,144 @@
1
+ /**
2
+ * GLM Daemon - Analyze Market Skill
3
+ *
4
+ * Analyze market conditions and identify trading opportunities.
5
+ */
6
+
7
+ import { z } from "zod";
8
+ import type { Skill, SkillContext, SkillResult } from "../types.js";
9
+ import { skillRegistry } from "../registry.js";
10
+
11
+ /**
12
+ * Analyze market parameters
13
+ */
14
+ const AnalyzeMarketParams = z.object({
15
+ /** Market symbol or ID */
16
+ symbol: z.string().optional(),
17
+ /** Analysis timeframe */
18
+ timeframe: z.enum(["short", "medium", "long"]).optional(),
19
+ /** Include sentiment analysis */
20
+ includeSentiment: z.boolean().optional(),
21
+ });
22
+
23
+ /**
24
+ * Market analysis result data
25
+ */
26
+ interface AnalyzeMarketData {
27
+ trend: "bullish" | "bearish" | "sideways";
28
+ confidence: number;
29
+ supportLevels: number[];
30
+ resistanceLevels: number[];
31
+ indicators: {
32
+ rsi?: number;
33
+ macd?: string;
34
+ volume?: string;
35
+ };
36
+ signals: string[];
37
+ riskLevel: "low" | "medium" | "high";
38
+ marketCondition: "volatile" | "ranging" | "trending";
39
+ }
40
+
41
+ /**
42
+ * Analyze market skill
43
+ */
44
+ export const analyzeMarketSkill: Skill<z.infer<typeof AnalyzeMarketParams>, AnalyzeMarketData> = {
45
+ id: "/analyze-market",
46
+ name: "Analyze Market",
47
+ description: "Analyze market conditions using technical indicators and sentiment.",
48
+ paramsSchema: AnalyzeMarketParams,
49
+ tags: ["trading", "analysis"],
50
+ parallelizable: true,
51
+ produces: ["analysis", "riskLevel", "marketCondition"],
52
+
53
+ async execute(params, context): Promise<SkillResult<AnalyzeMarketData>> {
54
+ const symbol = params?.symbol || context.custom.symbol || "current market";
55
+ const timeframe = params?.timeframe || "medium";
56
+
57
+ console.log(`[/analyze-market] Analyzing ${symbol} (${timeframe} term)`);
58
+
59
+ const prompt = `Analyze current market conditions for ${symbol}.
60
+
61
+ Consider:
62
+ - Price action and trends
63
+ - Volume analysis
64
+ - Technical indicators (RSI, MACD, Moving Averages)
65
+ - Market sentiment
66
+ - News and events (if known)
67
+ - Support and resistance levels
68
+ - Timeframe: ${timeframe}
69
+
70
+ Provide analysis in JSON format:
71
+ {
72
+ "trend": "bullish|bearish|sideways",
73
+ "confidence": 0-100,
74
+ "supportLevels": [price levels],
75
+ "resistanceLevels": [price levels],
76
+ "indicators": {
77
+ "rsi": number,
78
+ "macd": "bullish|bearish|neutral",
79
+ "volume": "high|medium|low"
80
+ },
81
+ "signals": ["list of trading signals"],
82
+ "riskLevel": "low|medium|high",
83
+ "marketCondition": "volatile|ranging|trending"
84
+ }`;
85
+
86
+ try {
87
+ const response = await context.agent.execute(prompt);
88
+
89
+ // Parse JSON from response
90
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
91
+ let data: AnalyzeMarketData;
92
+
93
+ if (jsonMatch) {
94
+ const parsed = JSON.parse(jsonMatch[0]);
95
+ data = {
96
+ trend: parsed.trend || "sideways",
97
+ confidence: parsed.confidence || 50,
98
+ supportLevels: parsed.supportLevels || [],
99
+ resistanceLevels: parsed.resistanceLevels || [],
100
+ indicators: parsed.indicators || {},
101
+ signals: parsed.signals || [],
102
+ riskLevel: parsed.riskLevel || "medium",
103
+ marketCondition: parsed.marketCondition || "ranging",
104
+ };
105
+ } else {
106
+ // Fallback
107
+ data = {
108
+ trend: "sideways",
109
+ confidence: 50,
110
+ supportLevels: [],
111
+ resistanceLevels: [],
112
+ indicators: {},
113
+ signals: ["Unable to parse analysis"],
114
+ riskLevel: "medium",
115
+ marketCondition: "ranging",
116
+ };
117
+ }
118
+
119
+ console.log(`[/analyze-market] Trend: ${data.trend} (${data.confidence}% confidence)`);
120
+ console.log(`[/analyze-market] Risk: ${data.riskLevel}, Condition: ${data.marketCondition}`);
121
+ console.log(`[/analyze-market] Signals: ${data.signals.length}`);
122
+
123
+ return {
124
+ success: true,
125
+ data,
126
+ contextUpdates: {
127
+ analysis: data,
128
+ riskLevel: data.riskLevel,
129
+ marketCondition: data.marketCondition,
130
+ },
131
+ };
132
+ } catch (error) {
133
+ return {
134
+ success: false,
135
+ error: error instanceof Error ? error.message : String(error),
136
+ };
137
+ }
138
+ },
139
+ };
140
+
141
+ skillRegistry.register(analyzeMarketSkill);
142
+
143
+ export { AnalyzeMarketParams };
144
+ export type { AnalyzeMarketData };