@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,176 @@
1
+ /**
2
+ * GLM Daemon - Check Risk Skill
3
+ *
4
+ * Evaluate risk and validate signal before execution.
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
+ * Trade signal from generate-signal skill
13
+ */
14
+ interface TradeSignal {
15
+ direction: "long" | "short" | "none";
16
+ entryZone?: { min: number; max: number };
17
+ stopLoss?: number;
18
+ takeProfits?: {
19
+ tp1?: { price: number; size: string };
20
+ tp2?: { price: number; size: string };
21
+ tp3?: { price: number; size: string };
22
+ };
23
+ confidence?: number;
24
+ rationale?: string;
25
+ positionSize?: {
26
+ percentage: number;
27
+ absolute?: number;
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Market analysis from analyze-market skill
33
+ */
34
+ interface MarketAnalysis {
35
+ marketId: string;
36
+ trend?: string;
37
+ volatility?: string;
38
+ sentiment?: string;
39
+ keyLevels?: number[];
40
+ }
41
+
42
+ /**
43
+ * Check risk parameters
44
+ */
45
+ const CheckRiskParams = z.object({
46
+ /** Maximum risk per trade (percentage) */
47
+ maxRiskPerTrade: z.number().optional(),
48
+ /** Minimum risk/reward ratio */
49
+ minRiskReward: z.number().optional(),
50
+ /** Maximum portfolio exposure */
51
+ maxExposure: z.number().optional(),
52
+ });
53
+
54
+ /**
55
+ * Risk check result data
56
+ */
57
+ interface CheckRiskData {
58
+ approved: boolean;
59
+ riskScore: number;
60
+ concerns: string[];
61
+ adjustments: string[];
62
+ maxPositionSize: number;
63
+ reasoning: string;
64
+ }
65
+
66
+ /**
67
+ * Check risk skill
68
+ */
69
+ export const checkRiskSkill: Skill<z.infer<typeof CheckRiskParams>, CheckRiskData> = {
70
+ id: "/check-risk",
71
+ name: "Check Risk",
72
+ description: "Evaluate risk and validate trading signal before execution.",
73
+ paramsSchema: CheckRiskParams,
74
+ tags: ["trading", "risk", "validation"],
75
+ parallelizable: false,
76
+ requires: ["analysis", "signal"],
77
+
78
+ async execute(params, context): Promise<SkillResult<CheckRiskData>> {
79
+ const analysis = (context.custom.analysis || {}) as MarketAnalysis;
80
+ const signal = (context.custom.signal || {}) as TradeSignal;
81
+ const maxRiskPerTrade = params?.maxRiskPerTrade || 2;
82
+ const minRiskReward = params?.minRiskReward || 1.5;
83
+ const maxExposure = params?.maxExposure || 10;
84
+
85
+ console.log("[/check-risk] Evaluating signal risk");
86
+
87
+ const prompt = `Perform risk assessment for the proposed trade.
88
+
89
+ Analysis: ${JSON.stringify(analysis, null, 2)}
90
+ Signal: ${JSON.stringify(signal, null, 2)}
91
+
92
+ Risk Parameters:
93
+ - Max risk per trade: ${maxRiskPerTrade}%
94
+ - Min risk/reward: ${minRiskReward}
95
+ - Max portfolio exposure: ${maxExposure}%
96
+
97
+ Evaluate:
98
+ 1. Risk/reward ratio (minimum ${minRiskReward}:1)
99
+ 2. Position size vs account risk (max ${maxRiskPerTrade}% per trade)
100
+ 3. Market conditions (avoid high volatility if conservative)
101
+ 4. Correlation with existing positions
102
+ 5. Stop loss placement validity
103
+
104
+ Respond in JSON format:
105
+ {
106
+ "approved": true|false,
107
+ "riskScore": 0-100,
108
+ "concerns": ["list of concerns"],
109
+ "adjustments": ["suggested adjustments"],
110
+ "maxPositionSize": number,
111
+ "reasoning": "detailed explanation"
112
+ }
113
+
114
+ If approved is false, explain why and what conditions would make it acceptable.`;
115
+
116
+ try {
117
+ const response = await context.agent.execute(prompt);
118
+
119
+ // Parse JSON from response
120
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
121
+ let data: CheckRiskData;
122
+
123
+ if (jsonMatch) {
124
+ const parsed = JSON.parse(jsonMatch[0]);
125
+ data = {
126
+ approved: parsed.approved === true,
127
+ riskScore: parsed.riskScore || 50,
128
+ concerns: parsed.concerns || [],
129
+ adjustments: parsed.adjustments || [],
130
+ maxPositionSize: parsed.maxPositionSize || signal.positionSize?.percentage || 1,
131
+ reasoning: parsed.reasoning || "",
132
+ };
133
+ } else {
134
+ // Fallback: default to not approved
135
+ const hasConcerns = response.toLowerCase().includes("concern") || response.toLowerCase().includes("risk");
136
+ data = {
137
+ approved: !hasConcerns,
138
+ riskScore: hasConcerns ? 70 : 30,
139
+ concerns: hasConcerns ? ["Unable to parse risk assessment"] : [],
140
+ adjustments: [],
141
+ maxPositionSize: 1,
142
+ reasoning: response.substring(0, 300),
143
+ };
144
+ }
145
+
146
+ console.log(`[/check-risk] Result: ${data.approved ? "APPROVED" : "REJECTED"}`);
147
+ console.log(`[/check-risk] Risk score: ${data.riskScore}/100`);
148
+ if (data.concerns.length > 0) {
149
+ console.log(`[/check-risk] Concerns: ${data.concerns.length}`);
150
+ }
151
+
152
+ return {
153
+ success: true,
154
+ data,
155
+ contextUpdates: {
156
+ riskApproved: data.approved,
157
+ riskAssessment: data,
158
+ },
159
+ nextSkill: data.approved ? "/execute-trade" : "/analyze-market",
160
+ };
161
+ } catch (error) {
162
+ return {
163
+ success: false,
164
+ error: error instanceof Error ? error.message : String(error),
165
+ contextUpdates: {
166
+ riskApproved: false,
167
+ },
168
+ };
169
+ }
170
+ },
171
+ };
172
+
173
+ skillRegistry.register(checkRiskSkill);
174
+
175
+ export { CheckRiskParams };
176
+ export type { CheckRiskData };
@@ -0,0 +1,185 @@
1
+ /**
2
+ * GLM Daemon - Execute Trade Skill
3
+ *
4
+ * Execute trades according to validated signals.
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
+ * Trade signal from generate-signal skill
13
+ */
14
+ interface TradeSignal {
15
+ direction: "long" | "short" | "none";
16
+ entryZone?: { min: number; max: number };
17
+ stopLoss?: number;
18
+ takeProfits?: {
19
+ tp1?: { price: number; size: string };
20
+ tp2?: { price: number; size: string };
21
+ tp3?: { price: number; size: string };
22
+ };
23
+ confidence?: number;
24
+ rationale?: string;
25
+ positionSize?: {
26
+ percentage: number;
27
+ absolute?: number;
28
+ };
29
+ }
30
+
31
+ /**
32
+ * Risk assessment from check-risk skill
33
+ */
34
+ interface RiskAssessment {
35
+ approved: boolean;
36
+ positionSize?: number;
37
+ riskPercent?: number;
38
+ riskRewardRatio?: number;
39
+ maxLoss?: number;
40
+ reasons?: string[];
41
+ }
42
+
43
+ /**
44
+ * Execute trade parameters
45
+ */
46
+ const ExecuteTradeParams = z.object({
47
+ /** Use paper trading (simulation) */
48
+ paper: z.boolean().optional(),
49
+ /** Custom order type */
50
+ orderType: z.enum(["market", "limit", "fok"]).optional(),
51
+ });
52
+
53
+ /**
54
+ * Execute trade result data
55
+ */
56
+ interface ExecuteTradeData {
57
+ orderId: string;
58
+ direction: string;
59
+ entryPrice: number;
60
+ size: number;
61
+ stopLossOrderId: string;
62
+ takeProfitOrderIds: string[];
63
+ status: "placed" | "filled" | "partial" | "failed";
64
+ timestamp: string;
65
+ }
66
+
67
+ /**
68
+ * Execute trade skill
69
+ */
70
+ export const executeTradeSkill: Skill<z.infer<typeof ExecuteTradeParams>, ExecuteTradeData> = {
71
+ id: "/execute-trade",
72
+ name: "Execute Trade",
73
+ description: "Execute trades using available trading tools.",
74
+ paramsSchema: ExecuteTradeParams,
75
+ tags: ["trading", "execution"],
76
+ parallelizable: false,
77
+ requires: ["signal", "riskApproved"],
78
+ maxRetries: 2,
79
+
80
+ async execute(params, context): Promise<SkillResult<ExecuteTradeData>> {
81
+ const signal = (context.custom.signal || {}) as TradeSignal;
82
+ const riskAssessment = (context.custom.riskAssessment || {}) as RiskAssessment;
83
+ const paper = params?.paper ?? true; // Default to paper trading
84
+
85
+ if (!context.custom.riskApproved) {
86
+ return {
87
+ success: false,
88
+ error: "Risk not approved - cannot execute trade",
89
+ };
90
+ }
91
+
92
+ console.log(`[/execute-trade] Executing ${signal.direction} trade (${paper ? "PAPER" : "LIVE"})`);
93
+
94
+ const prompt = `Execute the approved trade signal.
95
+
96
+ Signal: ${JSON.stringify(signal, null, 2)}
97
+ Risk Assessment: ${JSON.stringify(riskAssessment, null, 2)}
98
+ Mode: ${paper ? "PAPER TRADING" : "LIVE TRADING"}
99
+
100
+ Use the available trading tools to:
101
+ 1. Place the entry order (${params?.orderType || "limit"})
102
+ 2. Set stop loss order at ${signal.stopLoss}
103
+ 3. Set take profit orders:
104
+ - TP1 at ${signal.takeProfits?.tp1?.price} (${signal.takeProfits?.tp1?.size})
105
+ - TP2 at ${signal.takeProfits?.tp2?.price} (${signal.takeProfits?.tp2?.size})
106
+ - TP3 at ${signal.takeProfits?.tp3?.price} (${signal.takeProfits?.tp3?.size})
107
+ 4. Confirm all orders are placed correctly
108
+
109
+ Report execution status with order IDs in JSON format:
110
+ {
111
+ "orderId": "entry order id",
112
+ "direction": "long|short",
113
+ "entryPrice": number,
114
+ "size": number,
115
+ "stopLossOrderId": "stop loss order id",
116
+ "takeProfitOrderIds": ["tp1 id", "tp2 id", "tp3 id"],
117
+ "status": "placed|filled|partial|failed",
118
+ "timestamp": "ISO timestamp"
119
+ }`;
120
+
121
+ try {
122
+ const response = await context.agent.execute(prompt);
123
+
124
+ // Parse JSON from response
125
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
126
+ let data: ExecuteTradeData;
127
+
128
+ if (jsonMatch) {
129
+ const parsed = JSON.parse(jsonMatch[0]);
130
+ data = {
131
+ orderId: parsed.orderId || `paper-${Date.now()}`,
132
+ direction: parsed.direction || signal.direction,
133
+ entryPrice: parsed.entryPrice || signal.entryZone?.min || 0,
134
+ size: parsed.size || signal.positionSize?.percentage || 0,
135
+ stopLossOrderId: parsed.stopLossOrderId || `sl-${Date.now()}`,
136
+ takeProfitOrderIds: parsed.takeProfitOrderIds || [`tp1-${Date.now()}`, `tp2-${Date.now()}`, `tp3-${Date.now()}`],
137
+ status: parsed.status || "placed",
138
+ timestamp: parsed.timestamp || new Date().toISOString(),
139
+ };
140
+ } else {
141
+ // Fallback for paper trading
142
+ data = {
143
+ orderId: `paper-${Date.now()}`,
144
+ direction: signal.direction || "long",
145
+ entryPrice: signal.entryZone?.min || 0,
146
+ size: signal.positionSize?.percentage || 1,
147
+ stopLossOrderId: `sl-${Date.now()}`,
148
+ takeProfitOrderIds: [`tp1-${Date.now()}`, `tp2-${Date.now()}`, `tp3-${Date.now()}`],
149
+ status: "placed",
150
+ timestamp: new Date().toISOString(),
151
+ };
152
+ }
153
+
154
+ console.log(`[/execute-trade] Order ID: ${data.orderId}`);
155
+ console.log(`[/execute-trade] Status: ${data.status}`);
156
+ console.log(`[/execute-trade] Entry: ${data.entryPrice}, Size: ${data.size}%`);
157
+
158
+ return {
159
+ success: data.status !== "failed",
160
+ data,
161
+ contextUpdates: {
162
+ executionResult: data,
163
+ tradeStartTime: data.timestamp,
164
+ position: {
165
+ orderId: data.orderId,
166
+ direction: data.direction,
167
+ entryPrice: data.entryPrice,
168
+ size: data.size,
169
+ },
170
+ },
171
+ error: data.status === "failed" ? "Order execution failed" : undefined,
172
+ };
173
+ } catch (error) {
174
+ return {
175
+ success: false,
176
+ error: error instanceof Error ? error.message : String(error),
177
+ };
178
+ }
179
+ },
180
+ };
181
+
182
+ skillRegistry.register(executeTradeSkill);
183
+
184
+ export { ExecuteTradeParams };
185
+ export type { ExecuteTradeData };
@@ -0,0 +1,160 @@
1
+ /**
2
+ * GLM Daemon - Generate Signal Skill
3
+ *
4
+ * Generate trading signals based on market analysis.
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
+ * Generate signal parameters
13
+ */
14
+ const GenerateSignalParams = z.object({
15
+ /** Risk tolerance */
16
+ riskTolerance: z.enum(["conservative", "moderate", "aggressive"]).optional(),
17
+ /** Position size limit (percentage) */
18
+ maxPositionSize: z.number().optional(),
19
+ });
20
+
21
+ /**
22
+ * Trading signal result data
23
+ */
24
+ interface GenerateSignalData {
25
+ direction: "long" | "short" | "none";
26
+ entryZone: { min: number; max: number };
27
+ stopLoss: number;
28
+ takeProfits: {
29
+ tp1: { price: number; size: string };
30
+ tp2: { price: number; size: string };
31
+ tp3: { price: number; size: string };
32
+ };
33
+ positionSize: { percentage: number; reason: string };
34
+ riskReward: number;
35
+ confidence: number;
36
+ rationale: string;
37
+ }
38
+
39
+ /**
40
+ * Generate signal skill
41
+ */
42
+ export const generateSignalSkill: Skill<z.infer<typeof GenerateSignalParams>, GenerateSignalData> = {
43
+ id: "/generate-signal",
44
+ name: "Generate Signal",
45
+ description: "Generate trading signals based on market analysis.",
46
+ paramsSchema: GenerateSignalParams,
47
+ tags: ["trading", "signal"],
48
+ parallelizable: false,
49
+ requires: ["analysis"],
50
+
51
+ async execute(params, context): Promise<SkillResult<GenerateSignalData>> {
52
+ const analysis = context.custom.analysis || {};
53
+ const riskTolerance = params?.riskTolerance || "moderate";
54
+ const maxPositionSize = params?.maxPositionSize || 5;
55
+
56
+ console.log("[/generate-signal] Generating trading signal");
57
+
58
+ const prompt = `Generate a trading signal based on this analysis.
59
+
60
+ Analysis: ${JSON.stringify(analysis, null, 2)}
61
+ Risk Tolerance: ${riskTolerance}
62
+ Max Position Size: ${maxPositionSize}%
63
+
64
+ Generate a trading signal with:
65
+ - Direction (long/short/none)
66
+ - Entry price zone
67
+ - Stop loss level
68
+ - Take profit targets (3 levels)
69
+ - Position size recommendation
70
+ - Risk/reward ratio
71
+ - Confidence level
72
+ - Rationale
73
+
74
+ Provide the signal in JSON format:
75
+ {
76
+ "direction": "long|short|none",
77
+ "entryZone": { "min": number, "max": number },
78
+ "stopLoss": number,
79
+ "takeProfits": {
80
+ "tp1": { "price": number, "size": "percentage" },
81
+ "tp2": { "price": number, "size": "percentage" },
82
+ "tp3": { "price": number, "size": "percentage" }
83
+ },
84
+ "positionSize": { "percentage": number, "reason": "string" },
85
+ "riskReward": number,
86
+ "confidence": 0-100,
87
+ "rationale": "explanation"
88
+ }
89
+
90
+ If no clear signal exists, set direction to "none" and explain why.`;
91
+
92
+ try {
93
+ const response = await context.agent.execute(prompt);
94
+
95
+ // Parse JSON from response
96
+ const jsonMatch = response.match(/\{[\s\S]*\}/);
97
+ let data: GenerateSignalData;
98
+
99
+ if (jsonMatch) {
100
+ const parsed = JSON.parse(jsonMatch[0]);
101
+ data = {
102
+ direction: parsed.direction || "none",
103
+ entryZone: parsed.entryZone || { min: 0, max: 0 },
104
+ stopLoss: parsed.stopLoss || 0,
105
+ takeProfits: parsed.takeProfits || {
106
+ tp1: { price: 0, size: "33%" },
107
+ tp2: { price: 0, size: "33%" },
108
+ tp3: { price: 0, size: "34%" },
109
+ },
110
+ positionSize: parsed.positionSize || { percentage: 1, reason: "Default" },
111
+ riskReward: parsed.riskReward || 0,
112
+ confidence: parsed.confidence || 0,
113
+ rationale: parsed.rationale || "",
114
+ };
115
+ } else {
116
+ data = {
117
+ direction: "none",
118
+ entryZone: { min: 0, max: 0 },
119
+ stopLoss: 0,
120
+ takeProfits: {
121
+ tp1: { price: 0, size: "33%" },
122
+ tp2: { price: 0, size: "33%" },
123
+ tp3: { price: 0, size: "34%" },
124
+ },
125
+ positionSize: { percentage: 0, reason: "No valid signal" },
126
+ riskReward: 0,
127
+ confidence: 0,
128
+ rationale: response.substring(0, 200),
129
+ };
130
+ }
131
+
132
+ console.log(`[/generate-signal] Direction: ${data.direction}`);
133
+ console.log(`[/generate-signal] R:R = ${data.riskReward}, Confidence = ${data.confidence}%`);
134
+
135
+ // If no signal, go back to analysis
136
+ if (data.direction === "none") {
137
+ console.log("[/generate-signal] No signal generated, will re-analyze");
138
+ }
139
+
140
+ return {
141
+ success: true,
142
+ data,
143
+ contextUpdates: {
144
+ signal: data,
145
+ },
146
+ nextSkill: data.direction === "none" ? "/analyze-market" : undefined,
147
+ };
148
+ } catch (error) {
149
+ return {
150
+ success: false,
151
+ error: error instanceof Error ? error.message : String(error),
152
+ };
153
+ }
154
+ },
155
+ };
156
+
157
+ skillRegistry.register(generateSignalSkill);
158
+
159
+ export { GenerateSignalParams };
160
+ export type { GenerateSignalData };
@@ -0,0 +1,26 @@
1
+ /**
2
+ * GLM Daemon - Trading Skills
3
+ *
4
+ * Skills for trading and market analysis workflows.
5
+ */
6
+
7
+ // Import to auto-register
8
+ import "./analyze-market.js";
9
+ import "./generate-signal.js";
10
+ import "./check-risk.js";
11
+ import "./execute-trade.js";
12
+ import "./monitor-position.js";
13
+
14
+ // Re-export for explicit imports
15
+ export { analyzeMarketSkill } from "./analyze-market.js";
16
+ export { generateSignalSkill } from "./generate-signal.js";
17
+ export { checkRiskSkill } from "./check-risk.js";
18
+ export { executeTradeSkill } from "./execute-trade.js";
19
+ export { monitorPositionSkill } from "./monitor-position.js";
20
+
21
+ // Re-export types
22
+ export type { AnalyzeMarketData } from "./analyze-market.js";
23
+ export type { GenerateSignalData } from "./generate-signal.js";
24
+ export type { CheckRiskData } from "./check-risk.js";
25
+ export type { ExecuteTradeData } from "./execute-trade.js";
26
+ export type { MonitorPositionData } from "./monitor-position.js";