@ebowwa/daemons 0.5.1 → 0.7.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 (121) hide show
  1. package/dist/core.d.ts +89 -0
  2. package/dist/core.d.ts.map +1 -0
  3. package/dist/core.js +346 -0
  4. package/dist/core.js.map +1 -0
  5. package/dist/index.d.ts +16 -17
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +25 -125305
  8. package/dist/index.js.map +1 -0
  9. package/dist/types.d.ts +28 -273
  10. package/dist/types.d.ts.map +1 -1
  11. package/dist/types.js +7 -0
  12. package/dist/types.js.map +1 -0
  13. package/package.json +14 -65
  14. package/src/core.ts +476 -0
  15. package/src/index.ts +23 -101
  16. package/src/types.ts +24 -301
  17. package/dist/agent.d.ts +0 -37
  18. package/dist/agent.d.ts.map +0 -1
  19. package/dist/bin/discord-cli.js +0 -124083
  20. package/dist/bin/manager.js +0 -143
  21. package/dist/bin/telegram-cli.js +0 -124079
  22. package/dist/channels/base.d.ts +0 -163
  23. package/dist/channels/base.d.ts.map +0 -1
  24. package/dist/channels/discord.d.ts +0 -61
  25. package/dist/channels/discord.d.ts.map +0 -1
  26. package/dist/channels/index.d.ts +0 -55
  27. package/dist/channels/index.d.ts.map +0 -1
  28. package/dist/channels/telegram.d.ts +0 -113
  29. package/dist/channels/telegram.d.ts.map +0 -1
  30. package/dist/daemon.d.ts +0 -119
  31. package/dist/daemon.d.ts.map +0 -1
  32. package/dist/hooks.d.ts +0 -34
  33. package/dist/hooks.d.ts.map +0 -1
  34. package/dist/memory.d.ts +0 -151
  35. package/dist/memory.d.ts.map +0 -1
  36. package/dist/skills/coding/commit.d.ts +0 -31
  37. package/dist/skills/coding/commit.d.ts.map +0 -1
  38. package/dist/skills/coding/execute-subtask.d.ts +0 -30
  39. package/dist/skills/coding/execute-subtask.d.ts.map +0 -1
  40. package/dist/skills/coding/fix-issues.d.ts +0 -29
  41. package/dist/skills/coding/fix-issues.d.ts.map +0 -1
  42. package/dist/skills/coding/index.d.ts +0 -21
  43. package/dist/skills/coding/index.d.ts.map +0 -1
  44. package/dist/skills/coding/plan-task.d.ts +0 -38
  45. package/dist/skills/coding/plan-task.d.ts.map +0 -1
  46. package/dist/skills/coding/quality-check.d.ts +0 -35
  47. package/dist/skills/coding/quality-check.d.ts.map +0 -1
  48. package/dist/skills/index.d.ts +0 -38
  49. package/dist/skills/index.d.ts.map +0 -1
  50. package/dist/skills/registry.d.ts +0 -95
  51. package/dist/skills/registry.d.ts.map +0 -1
  52. package/dist/skills/shared/index.d.ts +0 -16
  53. package/dist/skills/shared/index.d.ts.map +0 -1
  54. package/dist/skills/shared/reflect.d.ts +0 -42
  55. package/dist/skills/shared/reflect.d.ts.map +0 -1
  56. package/dist/skills/shared/review.d.ts +0 -42
  57. package/dist/skills/shared/review.d.ts.map +0 -1
  58. package/dist/skills/shared/trajectory.d.ts +0 -80
  59. package/dist/skills/shared/trajectory.d.ts.map +0 -1
  60. package/dist/skills/trading/analyze-market.d.ts +0 -43
  61. package/dist/skills/trading/analyze-market.d.ts.map +0 -1
  62. package/dist/skills/trading/check-risk.d.ts +0 -33
  63. package/dist/skills/trading/check-risk.d.ts.map +0 -1
  64. package/dist/skills/trading/execute-trade.d.ts +0 -38
  65. package/dist/skills/trading/execute-trade.d.ts.map +0 -1
  66. package/dist/skills/trading/generate-signal.d.ts +0 -57
  67. package/dist/skills/trading/generate-signal.d.ts.map +0 -1
  68. package/dist/skills/trading/index.d.ts +0 -21
  69. package/dist/skills/trading/index.d.ts.map +0 -1
  70. package/dist/skills/trading/monitor-position.d.ts +0 -37
  71. package/dist/skills/trading/monitor-position.d.ts.map +0 -1
  72. package/dist/skills/types.d.ts +0 -173
  73. package/dist/skills/types.d.ts.map +0 -1
  74. package/dist/skills/workflows.d.ts +0 -36
  75. package/dist/skills/workflows.d.ts.map +0 -1
  76. package/dist/state.d.ts +0 -31
  77. package/dist/state.d.ts.map +0 -1
  78. package/dist/tools.d.ts +0 -42
  79. package/dist/tools.d.ts.map +0 -1
  80. package/dist/workflow.d.ts +0 -182
  81. package/dist/workflow.d.ts.map +0 -1
  82. package/dist/workflows/coding.d.ts +0 -79
  83. package/dist/workflows/coding.d.ts.map +0 -1
  84. package/dist/workflows/index.d.ts +0 -24
  85. package/dist/workflows/index.d.ts.map +0 -1
  86. package/dist/workflows/trading.d.ts +0 -72
  87. package/dist/workflows/trading.d.ts.map +0 -1
  88. package/src/agent.ts +0 -111
  89. package/src/channels/base.ts +0 -574
  90. package/src/channels/discord.ts +0 -306
  91. package/src/channels/index.ts +0 -169
  92. package/src/channels/telegram.ts +0 -316
  93. package/src/daemon.ts +0 -534
  94. package/src/hooks.ts +0 -97
  95. package/src/memory.ts +0 -369
  96. package/src/skills/coding/commit.ts +0 -202
  97. package/src/skills/coding/execute-subtask.ts +0 -136
  98. package/src/skills/coding/fix-issues.ts +0 -126
  99. package/src/skills/coding/index.ts +0 -26
  100. package/src/skills/coding/plan-task.ts +0 -158
  101. package/src/skills/coding/quality-check.ts +0 -155
  102. package/src/skills/index.ts +0 -65
  103. package/src/skills/registry.ts +0 -380
  104. package/src/skills/shared/index.ts +0 -21
  105. package/src/skills/shared/reflect.ts +0 -156
  106. package/src/skills/shared/review.ts +0 -201
  107. package/src/skills/shared/trajectory.ts +0 -326
  108. package/src/skills/trading/analyze-market.ts +0 -144
  109. package/src/skills/trading/check-risk.ts +0 -176
  110. package/src/skills/trading/execute-trade.ts +0 -185
  111. package/src/skills/trading/generate-signal.ts +0 -160
  112. package/src/skills/trading/index.ts +0 -26
  113. package/src/skills/trading/monitor-position.ts +0 -179
  114. package/src/skills/types.ts +0 -235
  115. package/src/skills/workflows.ts +0 -340
  116. package/src/state.ts +0 -77
  117. package/src/tools.ts +0 -134
  118. package/src/workflow.ts +0 -341
  119. package/src/workflows/coding.ts +0 -580
  120. package/src/workflows/index.ts +0 -61
  121. package/src/workflows/trading.ts +0 -608
package/src/memory.ts DELETED
@@ -1,369 +0,0 @@
1
- /**
2
- * Conversation Memory - Generic conversation tracking for any channel
3
- *
4
- * Tracks chat history per user/conversation with persistence.
5
- * Can be used by Telegram, Discord, or any other channel.
6
- *
7
- * Storage format: JSONL (JSON Lines)
8
- * Each line is a JSON object: {"id": "...", "messages": [...], "lastUpdated": timestamp}
9
- */
10
-
11
- import {
12
- readFileSync,
13
- writeFileSync,
14
- existsSync,
15
- mkdirSync,
16
- renameSync,
17
- } from "fs";
18
- import { dirname } from "path";
19
-
20
- /**
21
- * A single message in a conversation
22
- */
23
- export interface ConversationMessage {
24
- role: "user" | "assistant" | "system";
25
- content: string;
26
- timestamp?: number;
27
- }
28
-
29
- /**
30
- * Internal storage format for JSONL
31
- */
32
- interface ConversationEntry {
33
- id: string;
34
- messages: ConversationMessage[];
35
- lastUpdated: number;
36
- }
37
-
38
- /**
39
- * Configuration for ConversationMemory
40
- */
41
- export interface ConversationMemoryConfig {
42
- /** Path to persistence file (default: ./conversations.jsonl) */
43
- file?: string;
44
- /** Maximum messages to keep per conversation (default: 10) */
45
- maxMessages?: number;
46
- /** Include timestamps in messages (default: true) */
47
- includeTimestamps?: boolean;
48
- /** Auto-migrate old .json files to .jsonl (default: true) */
49
- autoMigrate?: boolean;
50
- }
51
-
52
- /**
53
- * Generic conversation memory that tracks chat history per conversation ID.
54
- *
55
- * Uses JSONL format for efficient append-only writes and streaming reads.
56
- * Automatically migrates from old JSON format on first load.
57
- *
58
- * The ID type is generic (string | number) to support different channel types:
59
- * - Telegram: number (chatId)
60
- * - Discord: string (channelId/userId)
61
- * - Slack: string (channelId)
62
- *
63
- * @example
64
- * ```ts
65
- * const memory = new ConversationMemory({ maxMessages: 20 });
66
- * memory.add(12345, 'user', 'Hello!');
67
- * memory.add(12345, 'assistant', 'Hi there!');
68
- * const history = memory.get(12345);
69
- * ```
70
- */
71
- export class ConversationMemory<IdType = string | number> {
72
- private conversations = new Map<IdType, ConversationMessage[]>();
73
- private maxMessages: number;
74
- private includeTimestamps: boolean;
75
- private file: string;
76
- private needsFullSave = false;
77
-
78
- constructor(config: ConversationMemoryConfig = {}) {
79
- // Default to .jsonl extension
80
- const defaultFile = "./conversations.jsonl";
81
- this.file = config.file || defaultFile;
82
-
83
- // Auto-migrate from .json to .jsonl if needed
84
- if (config.autoMigrate !== false && !existsSync(this.file)) {
85
- this.migrateFromJson(this.file);
86
- }
87
-
88
- this.maxMessages = config.maxMessages ?? 10;
89
- this.includeTimestamps = config.includeTimestamps ?? true;
90
- this.load();
91
- }
92
-
93
- /**
94
- * Migrate from old JSON format to JSONL
95
- */
96
- private migrateFromJson(jsonlFile: string): void {
97
- // Check for old .json file
98
- const jsonFile = jsonlFile.replace(/\.jsonl$/, ".json");
99
- if (!existsSync(jsonFile)) return;
100
-
101
- try {
102
- const data = JSON.parse(readFileSync(jsonFile, "utf-8"));
103
- const entries: ConversationEntry[] = [];
104
-
105
- for (const [id, messages] of Object.entries(data)) {
106
- entries.push({
107
- id,
108
- messages: messages as ConversationMessage[],
109
- lastUpdated: Date.now(),
110
- });
111
- }
112
-
113
- // Write as JSONL
114
- const dir = dirname(jsonlFile);
115
- if (!existsSync(dir)) {
116
- mkdirSync(dir, { recursive: true });
117
- }
118
-
119
- const lines = entries.map((e) => JSON.stringify(e)).join("\n");
120
- writeFileSync(jsonlFile, lines + (lines ? "\n" : ""));
121
-
122
- // Backup old file instead of deleting
123
- const backupFile = jsonFile + ".backup";
124
- renameSync(jsonFile, backupFile);
125
-
126
- console.log(`Migrated ${jsonFile} to ${jsonlFile} (${entries.length} conversations)`);
127
- } catch (error) {
128
- console.error(`Migration failed: ${error}`);
129
- }
130
- }
131
-
132
- /**
133
- * Load conversations from JSONL file
134
- * Uses synchronous read for constructor compatibility
135
- */
136
- private load(): void {
137
- if (!existsSync(this.file)) return;
138
-
139
- try {
140
- const content = readFileSync(this.file, "utf-8");
141
- const lines = content.split("\n");
142
-
143
- for (const line of lines) {
144
- if (!line.trim()) continue;
145
- try {
146
- const entry: ConversationEntry = JSON.parse(line);
147
- const key = this.parseKey(entry.id);
148
- this.conversations.set(key, entry.messages);
149
- } catch {
150
- // Skip malformed lines
151
- }
152
- }
153
- } catch {
154
- // Start fresh on error
155
- }
156
- }
157
-
158
- /**
159
- * Parse string key back to original type
160
- */
161
- private parseKey(id: string): IdType {
162
- // Try to parse as number if it looks like one
163
- if (/^-?\d+$/.test(id)) {
164
- return Number(id) as IdType;
165
- }
166
- return id as IdType;
167
- }
168
-
169
- /**
170
- * Convert IdType to string for storage
171
- */
172
- private stringifyKey(id: IdType): string {
173
- return String(id);
174
- }
175
-
176
- /**
177
- * Save all conversations to disk (full rewrite)
178
- * Used when entries are deleted or modified
179
- */
180
- private saveFull(): void {
181
- try {
182
- const dir = dirname(this.file);
183
- if (!existsSync(dir)) {
184
- mkdirSync(dir, { recursive: true });
185
- }
186
-
187
- const lines: string[] = [];
188
- for (const [id, messages] of this.conversations) {
189
- const entry: ConversationEntry = {
190
- id: this.stringifyKey(id),
191
- messages,
192
- lastUpdated: Date.now(),
193
- };
194
- lines.push(JSON.stringify(entry));
195
- }
196
-
197
- writeFileSync(this.file, lines.join("\n") + (lines.length ? "\n" : ""));
198
- this.needsFullSave = false;
199
- } catch (error) {
200
- console.error(`Save failed: ${error}`);
201
- }
202
- }
203
-
204
- /**
205
- * Append a single entry to the file (efficient for adds)
206
- */
207
- private appendEntry(conversationId: IdType, messages: ConversationMessage[]): void {
208
- try {
209
- const dir = dirname(this.file);
210
- if (!existsSync(dir)) {
211
- mkdirSync(dir, { recursive: true });
212
- }
213
-
214
- const entry: ConversationEntry = {
215
- id: this.stringifyKey(conversationId),
216
- messages,
217
- lastUpdated: Date.now(),
218
- };
219
-
220
- // Check if file exists and has content to determine if we need newline
221
- const hasContent = existsSync(this.file) && readFileSync(this.file, "utf-8").length > 0;
222
- const prefix = hasContent ? "" : "";
223
- const line = JSON.stringify(entry) + "\n";
224
-
225
- // We need to do a full save to replace the old entry for this conversation
226
- // JSONL doesn't support in-place updates, so we mark for full save
227
- this.needsFullSave = true;
228
-
229
- // For now, do a full save since we need to replace the entry
230
- this.saveFull();
231
- } catch (error) {
232
- console.error(`Append failed: ${error}`);
233
- }
234
- }
235
-
236
- /**
237
- * Add a message to a conversation
238
- */
239
- add(
240
- conversationId: IdType,
241
- role: "user" | "assistant" | "system",
242
- content: string
243
- ): void {
244
- if (!this.conversations.has(conversationId)) {
245
- this.conversations.set(conversationId, []);
246
- }
247
-
248
- const history = this.conversations.get(conversationId)!;
249
- const message: ConversationMessage = { role, content };
250
-
251
- if (this.includeTimestamps) {
252
- message.timestamp = Date.now();
253
- }
254
-
255
- history.push(message);
256
-
257
- // Keep only last N messages
258
- if (history.length > this.maxMessages) {
259
- history.splice(0, history.length - this.maxMessages);
260
- }
261
-
262
- // Save the updated conversation
263
- this.appendEntry(conversationId, history);
264
- }
265
-
266
- /**
267
- * Get conversation history for a specific conversation
268
- */
269
- get(conversationId: IdType): ConversationMessage[] {
270
- return this.conversations.get(conversationId) || [];
271
- }
272
-
273
- /**
274
- * Get all conversations
275
- */
276
- getAll(): Map<IdType, ConversationMessage[]> {
277
- return new Map(this.conversations);
278
- }
279
-
280
- /**
281
- * Clear a specific conversation
282
- */
283
- clear(conversationId: IdType): void {
284
- this.conversations.delete(conversationId);
285
- this.saveFull();
286
- }
287
-
288
- /**
289
- * Clear all conversations
290
- */
291
- clearAll(): void {
292
- this.conversations.clear();
293
- this.saveFull();
294
- }
295
-
296
- /**
297
- * Check if a conversation exists
298
- */
299
- has(conversationId: IdType): boolean {
300
- return this.conversations.has(conversationId);
301
- }
302
-
303
- /**
304
- * Get the number of conversations
305
- */
306
- size(): number {
307
- return this.conversations.size;
308
- }
309
-
310
- /**
311
- * Get the messages count for a specific conversation
312
- */
313
- messageCount(conversationId: IdType): number {
314
- return this.conversations.get(conversationId)?.length || 0;
315
- }
316
-
317
- /**
318
- * Get formatted history for API calls (OpenAI/Anthropic format)
319
- */
320
- getForAPI(
321
- conversationId: IdType
322
- ): Array<{ role: string; content: string }> {
323
- return this.get(conversationId).map(({ role, content }) => ({
324
- role,
325
- content,
326
- }));
327
- }
328
-
329
- /**
330
- * Force a full save (useful before shutdown)
331
- */
332
- flush(): void {
333
- if (this.needsFullSave || this.conversations.size > 0) {
334
- this.saveFull();
335
- }
336
- }
337
-
338
- /**
339
- * Get the file path being used
340
- */
341
- getFilePath(): string {
342
- return this.file;
343
- }
344
-
345
- /**
346
- * Check if the storage uses JSONL format
347
- */
348
- isJsonl(): boolean {
349
- return this.file.endsWith(".jsonl");
350
- }
351
- }
352
-
353
- /**
354
- * Pre-configured memory for numeric IDs (like Telegram chat IDs)
355
- */
356
- export class NumericConversationMemory extends ConversationMemory<number> {
357
- constructor(config: Omit<ConversationMemoryConfig, "file"> & { file?: string } = {}) {
358
- super(config);
359
- }
360
- }
361
-
362
- /**
363
- * Pre-configured memory for string IDs (like Discord/Slack channel IDs)
364
- */
365
- export class StringConversationMemory extends ConversationMemory<string> {
366
- constructor(config: Omit<ConversationMemoryConfig, "file"> & { file?: string } = {}) {
367
- super(config);
368
- }
369
- }
@@ -1,202 +0,0 @@
1
- /**
2
- * GLM Daemon - Commit Skill
3
- *
4
- * Commit changes to git with auto-generated message.
5
- */
6
-
7
- import { z } from "zod";
8
- import { exec } from "child_process";
9
- import { promisify } from "util";
10
- import type { Skill, SkillContext, SkillResult } from "../types.js";
11
- import { skillRegistry } from "../registry.js";
12
-
13
- const execAsync = promisify(exec);
14
-
15
- /**
16
- * Commit parameters
17
- */
18
- const CommitParams = z.object({
19
- /** Custom commit message */
20
- message: z.string().optional(),
21
- /** Whether to push after commit */
22
- push: z.boolean().optional(),
23
- /** Skip hooks */
24
- noVerify: z.boolean().optional(),
25
- });
26
-
27
- /**
28
- * Commit result data
29
- */
30
- interface CommitData {
31
- commitHash: string;
32
- message: string;
33
- filesCount: number;
34
- pushed: boolean;
35
- }
36
-
37
- /**
38
- * Commit skill
39
- */
40
- export const commitSkill: Skill<z.infer<typeof CommitParams>, CommitData> = {
41
- id: "/commit",
42
- name: "Commit",
43
- description: "Commit changes to git with an auto-generated or custom message.",
44
- paramsSchema: CommitParams,
45
- tags: ["coding", "git"],
46
- parallelizable: false,
47
-
48
- async execute(params, context): Promise<SkillResult<CommitData>> {
49
- const filesCount = context.state.filesChanged.length;
50
-
51
- if (filesCount === 0) {
52
- console.log("[/commit] No files to commit");
53
- return {
54
- success: true,
55
- data: {
56
- commitHash: "",
57
- message: "No changes to commit",
58
- filesCount: 0,
59
- pushed: false,
60
- },
61
- nextSkill: "/complete",
62
- };
63
- }
64
-
65
- console.log(`[/commit] Committing ${filesCount} files`);
66
-
67
- // Generate commit message if not provided
68
- let message = params?.message;
69
- if (!message) {
70
- const prompt = `Generate a concise git commit message for these changes:
71
-
72
- Task: ${context.state.prompt}
73
- Files: ${context.state.filesChanged.join(", ")}
74
-
75
- Format: <type>: <description>
76
-
77
- Types: feat, fix, refactor, docs, test, chore
78
-
79
- Just output the commit message, nothing else.`;
80
-
81
- const response = await context.agent.execute(prompt);
82
- message = response.split("\n")[0].trim();
83
- }
84
-
85
- console.log(`[/commit] Message: ${message}`);
86
-
87
- // Get the working directory from workflow config or use current directory
88
- const cwd = (context.workflowConfig?.cwd as string) || process.cwd();
89
- const pushed = params?.push ?? false;
90
-
91
- try {
92
- // Step 1: Stage all changed files
93
- const filesToStage = context.state.filesChanged.length > 0
94
- ? context.state.filesChanged.join(" ")
95
- : "."; // Stage all if no specific files tracked
96
-
97
- console.log(`[/commit] Staging files: ${filesToStage}`);
98
- await execAsync(`git add ${filesToStage}`, { cwd });
99
-
100
- // Step 2: Commit with message
101
- const noVerifyFlag = params?.noVerify ? " --no-verify" : "";
102
- const escapedMessage = message.replace(/"/g, '\\"');
103
- const commitCommand = `git commit -m "${escapedMessage}"${noVerifyFlag}`;
104
-
105
- console.log(`[/commit] Executing commit...`);
106
- const { stdout: commitOutput } = await execAsync(commitCommand, { cwd });
107
-
108
- // Extract commit hash from output (format: [main abc1234] message)
109
- const hashMatch = commitOutput.match(/\[[\w-]+\s+([a-f0-9]+)\]/);
110
- const commitHash = hashMatch ? hashMatch[1] : "";
111
-
112
- if (!commitHash) {
113
- console.warn("[/commit] Could not extract commit hash from output");
114
- }
115
-
116
- console.log(`[/commit] Committed: ${commitHash}`);
117
-
118
- // Step 3: Push if requested
119
- if (pushed) {
120
- console.log(`[/commit] Pushing to remote...`);
121
- try {
122
- await execAsync("git push", { cwd });
123
- console.log(`[/commit] Pushed successfully`);
124
- } catch (pushError) {
125
- console.error("[/commit] Push failed:", pushError);
126
- // Don't fail the whole commit if push fails
127
- return {
128
- success: true,
129
- data: {
130
- commitHash,
131
- message: message || "Changes committed",
132
- filesCount,
133
- pushed: false,
134
- },
135
- contextUpdates: {
136
- lastCommit: commitHash,
137
- lastCommitMessage: message,
138
- },
139
- stateUpdates: {
140
- git: {
141
- ...context.state.git,
142
- currentCommit: commitHash,
143
- },
144
- },
145
- nextSkill: "/complete",
146
- error: `Commit succeeded but push failed: ${pushError instanceof Error ? pushError.message : String(pushError)}`,
147
- };
148
- }
149
- }
150
-
151
- return {
152
- success: true,
153
- data: {
154
- commitHash,
155
- message: message || "Changes committed",
156
- filesCount,
157
- pushed,
158
- },
159
- contextUpdates: {
160
- lastCommit: commitHash,
161
- lastCommitMessage: message,
162
- },
163
- stateUpdates: {
164
- git: {
165
- ...context.state.git,
166
- currentCommit: commitHash,
167
- },
168
- },
169
- nextSkill: "/complete",
170
- };
171
- } catch (error) {
172
- const errorMessage = error instanceof Error ? error.message : String(error);
173
- console.error("[/commit] Git operation failed:", errorMessage);
174
-
175
- // Check if it's just "nothing to commit"
176
- if (errorMessage.includes("nothing to commit") || errorMessage.includes("no changes added to commit")) {
177
- console.log("[/commit] No changes to commit (already clean)");
178
- return {
179
- success: true,
180
- data: {
181
- commitHash: context.state.git.currentCommit || "",
182
- message: "No changes to commit",
183
- filesCount: 0,
184
- pushed: false,
185
- },
186
- nextSkill: "/complete",
187
- };
188
- }
189
-
190
- return {
191
- success: false,
192
- error: `Git operation failed: ${errorMessage}`,
193
- nextSkill: "/fix-issues",
194
- };
195
- }
196
- },
197
- };
198
-
199
- skillRegistry.register(commitSkill);
200
-
201
- export { CommitParams };
202
- export type { CommitData };
@@ -1,136 +0,0 @@
1
- /**
2
- * GLM Daemon - Execute Subtask Skill
3
- *
4
- * Work on the current subtask from the plan.
5
- */
6
-
7
- import { z } from "zod";
8
- import type { Skill, SkillContext, SkillResult } from "../types.js";
9
- import { skillRegistry } from "../registry.js";
10
- import type { Subtask } from "./plan-task.js";
11
-
12
- /**
13
- * Execute subtask parameters
14
- */
15
- const ExecuteSubtaskParams = z.object({
16
- /** Specific subtask ID to execute (defaults to current) */
17
- subtaskId: z.string().optional(),
18
- });
19
-
20
- /**
21
- * Execute subtask result data
22
- */
23
- interface ExecuteSubtaskData {
24
- subtaskId: string;
25
- title: string;
26
- result: string;
27
- completed: boolean;
28
- nextSubtaskId: string | null;
29
- }
30
-
31
- /**
32
- * Execute subtask skill
33
- */
34
- export const executeSubtaskSkill: Skill<z.infer<typeof ExecuteSubtaskParams>, ExecuteSubtaskData> = {
35
- id: "/execute-subtask",
36
- name: "Execute Subtask",
37
- description: "Work on the current subtask using available tools.",
38
- paramsSchema: ExecuteSubtaskParams,
39
- tags: ["coding", "execution"],
40
- parallelizable: false,
41
- requires: ["subtasks"],
42
-
43
- async execute(params, context): Promise<SkillResult<ExecuteSubtaskData>> {
44
- // Get subtask to execute
45
- const subtaskId = params?.subtaskId || context.state.slam.currentSubtask;
46
-
47
- if (!subtaskId) {
48
- console.log("[/execute-subtask] No current subtask, all complete");
49
- return {
50
- success: true,
51
- data: {
52
- subtaskId: "",
53
- title: "",
54
- result: "All subtasks complete",
55
- completed: true,
56
- nextSubtaskId: null,
57
- },
58
- nextSkill: "/quality-check",
59
- };
60
- }
61
-
62
- const subtask = context.state.slam.subtasks.find((st) => st.id === subtaskId) as Subtask | undefined;
63
-
64
- if (!subtask) {
65
- return {
66
- success: false,
67
- error: `Subtask not found: ${subtaskId}`,
68
- };
69
- }
70
-
71
- console.log(`[/execute-subtask] Working on: ${subtask.title}`);
72
-
73
- const prompt = `Work on this subtask: ${subtask.title}
74
-
75
- ${subtask.description}
76
-
77
- Use available tools to complete the work.
78
- Focus on making concrete progress.
79
-
80
- When done, briefly summarize what was accomplished.`;
81
-
82
- try {
83
- const result = await context.agent.execute(prompt);
84
-
85
- // Mark subtask as completed
86
- const completedSubtasks = [...new Set([...context.state.slam.completedSubtasks, subtaskId])];
87
- const updatedSubtasks = context.state.slam.subtasks.map((st) =>
88
- st.id === subtaskId ? { ...st, status: "completed" as const, result } : st
89
- );
90
-
91
- // Find next subtask (that isn't completed and has dependencies met)
92
- const nextSubtask = context.state.slam.subtasks.find(
93
- (st) => !completedSubtasks.includes(st.id) && (!st.dependencies || st.dependencies.every((d) => completedSubtasks.includes(d)))
94
- );
95
-
96
- const allComplete = completedSubtasks.length === context.state.slam.subtasks.length;
97
-
98
- console.log(`[/execute-subtask] Completed: ${subtask.title}`);
99
- console.log(`[/execute-subtask] Progress: ${completedSubtasks.length}/${context.state.slam.subtasks.length}`);
100
-
101
- return {
102
- success: true,
103
- data: {
104
- subtaskId,
105
- title: subtask.title,
106
- result: result.substring(0, 500),
107
- completed: allComplete,
108
- nextSubtaskId: nextSubtask?.id || null,
109
- },
110
- stateUpdates: {
111
- slam: {
112
- ...context.state.slam,
113
- subtasks: updatedSubtasks,
114
- currentSubtask: nextSubtask?.id || null,
115
- completedSubtasks,
116
- },
117
- },
118
- contextUpdates: {
119
- currentSubtask: nextSubtask?.id || null,
120
- lastCompletedSubtask: subtaskId,
121
- },
122
- nextSkill: allComplete ? "/quality-check" : undefined,
123
- };
124
- } catch (error) {
125
- return {
126
- success: false,
127
- error: error instanceof Error ? error.message : String(error),
128
- };
129
- }
130
- },
131
- };
132
-
133
- skillRegistry.register(executeSubtaskSkill);
134
-
135
- export { ExecuteSubtaskParams };
136
- export type { ExecuteSubtaskData };