@ebowwa/glm-daemon 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +264 -0
  2. package/dist/agent.d.ts +37 -0
  3. package/dist/agent.d.ts.map +1 -0
  4. package/dist/agent.js +97 -0
  5. package/dist/agent.js.map +1 -0
  6. package/dist/daemon.d.ts +91 -0
  7. package/dist/daemon.d.ts.map +1 -0
  8. package/dist/daemon.js +449 -0
  9. package/dist/daemon.js.map +1 -0
  10. package/dist/hooks.d.ts +34 -0
  11. package/dist/hooks.d.ts.map +1 -0
  12. package/dist/hooks.js +82 -0
  13. package/dist/hooks.js.map +1 -0
  14. package/dist/index.d.ts +21 -0
  15. package/dist/index.d.ts.map +1 -0
  16. package/dist/index.js +31 -0
  17. package/dist/index.js.map +1 -0
  18. package/dist/state.d.ts +31 -0
  19. package/dist/state.d.ts.map +1 -0
  20. package/dist/state.js +67 -0
  21. package/dist/state.js.map +1 -0
  22. package/dist/tools.d.ts +42 -0
  23. package/dist/tools.d.ts.map +1 -0
  24. package/dist/tools.js +110 -0
  25. package/dist/tools.js.map +1 -0
  26. package/dist/types.d.ts +222 -0
  27. package/dist/types.d.ts.map +1 -0
  28. package/dist/types.js +19 -0
  29. package/dist/types.js.map +1 -0
  30. package/dist/worktree.d.ts +42 -0
  31. package/dist/worktree.d.ts.map +1 -0
  32. package/dist/worktree.js +86 -0
  33. package/dist/worktree.js.map +1 -0
  34. package/package.json +70 -0
  35. package/src/agent.js +166 -0
  36. package/src/agent.ts +110 -0
  37. package/src/daemon.js +591 -0
  38. package/src/daemon.ts +529 -0
  39. package/src/hooks.js +145 -0
  40. package/src/hooks.ts +94 -0
  41. package/src/index.js +105 -0
  42. package/src/index.ts +43 -0
  43. package/src/state.js +168 -0
  44. package/src/state.ts +77 -0
  45. package/src/tools.js +192 -0
  46. package/src/tools.ts +134 -0
  47. package/src/types.js +21 -0
  48. package/src/types.ts +249 -0
  49. package/src/worktree.js +195 -0
  50. package/src/worktree.ts +122 -0
package/src/tools.ts ADDED
@@ -0,0 +1,134 @@
1
+ /**
2
+ * GLM Daemon - Tool Bridge
3
+ *
4
+ * Connects GLM agents to MCP servers for tool access.
5
+ */
6
+
7
+ import type { GLMToolsConfig } from "./types.js";
8
+
9
+ export class ToolBridge {
10
+ private config: GLMToolsConfig;
11
+ private availableTools: string[] = [];
12
+ private toolTimeout: number;
13
+ private maxRetries: number;
14
+
15
+ constructor(config: GLMToolsConfig = {}) {
16
+ this.config = config;
17
+ this.toolTimeout = config.toolTimeout || 30000;
18
+ this.maxRetries = config.maxRetries || 3;
19
+ }
20
+
21
+ /**
22
+ * Get list of available tools
23
+ */
24
+ getAvailableTools(): string[] {
25
+ return this.availableTools;
26
+ }
27
+
28
+ /**
29
+ * Set available tools (from MCP discovery)
30
+ */
31
+ setAvailableTools(tools: string[]): void {
32
+ this.availableTools = tools;
33
+ }
34
+
35
+ /**
36
+ * Check if a tool is allowed
37
+ */
38
+ isToolAllowed(toolName: string): boolean {
39
+ // Check blacklist first
40
+ if (this.config.blockedTools?.includes(toolName)) {
41
+ return false;
42
+ }
43
+
44
+ // If whitelist exists, check it
45
+ if (this.config.allowedTools && this.config.allowedTools.length > 0) {
46
+ return this.config.allowedTools.includes(toolName);
47
+ }
48
+
49
+ // Default: allow if not blocked
50
+ return true;
51
+ }
52
+
53
+ /**
54
+ * Execute a tool with timeout and retry
55
+ */
56
+ async executeTool(
57
+ toolName: string,
58
+ args: Record<string, unknown>
59
+ ): Promise<{ success: boolean; result?: unknown; error?: string }> {
60
+ if (!this.isToolAllowed(toolName)) {
61
+ return {
62
+ success: false,
63
+ error: `Tool not allowed: ${toolName}`,
64
+ };
65
+ }
66
+
67
+ let lastError: Error | null = null;
68
+
69
+ for (let attempt = 0; attempt < this.maxRetries; attempt++) {
70
+ try {
71
+ const result = await this.executeWithTimeout(toolName, args);
72
+ return { success: true, result };
73
+ } catch (error) {
74
+ lastError = error as Error;
75
+ // Wait before retry (exponential backoff)
76
+ if (attempt < this.maxRetries - 1) {
77
+ await new Promise((resolve) =>
78
+ setTimeout(resolve, Math.pow(2, attempt) * 1000)
79
+ );
80
+ }
81
+ }
82
+ }
83
+
84
+ return {
85
+ success: false,
86
+ error: lastError?.message || "Unknown error",
87
+ };
88
+ }
89
+
90
+ /**
91
+ * Execute tool with timeout
92
+ */
93
+ private async executeWithTimeout(
94
+ toolName: string,
95
+ args: Record<string, unknown>
96
+ ): Promise<unknown> {
97
+ return new Promise((resolve, reject) => {
98
+ const timer = setTimeout(() => {
99
+ reject(new Error(`Tool timeout: ${toolName}`));
100
+ }, this.toolTimeout);
101
+
102
+ // TODO: Actually call MCP tool here
103
+ // For now, this is a placeholder
104
+ setTimeout(() => {
105
+ clearTimeout(timer);
106
+ resolve(`Executed ${toolName} with ${JSON.stringify(args)}`);
107
+ }, 100);
108
+ });
109
+ }
110
+
111
+ /**
112
+ * Discover tools from MCP servers
113
+ */
114
+ async discoverMCPTools(): Promise<void> {
115
+ if (!this.config.enableMCP) {
116
+ return;
117
+ }
118
+
119
+ // TODO: Query MCP servers for available tools
120
+ // For now, add common tools
121
+ const commonTools = [
122
+ "Read",
123
+ "Write",
124
+ "Edit",
125
+ "Grep",
126
+ "Glob",
127
+ "Bash",
128
+ "git_status",
129
+ "git_commit",
130
+ ];
131
+
132
+ this.setAvailableTools(commonTools);
133
+ }
134
+ }
package/src/types.js ADDED
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ /**
3
+ * GLM Daemon - Core Types
4
+ *
5
+ * Autonomous AI daemon powered by GLM 4.7 with hooks, tools, and teammates.
6
+ * Based on Ralph Iterative's SLAM pattern (State → Loop → Action → Memory).
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.GLM_PHASES = void 0;
10
+ /**
11
+ * GLM Daemon state phases (SLAM pattern)
12
+ */
13
+ exports.GLM_PHASES = {
14
+ planning: "planning",
15
+ executing: "executing",
16
+ paranoid: "paranoid",
17
+ reviewing: "reviewing",
18
+ fixing: "fixing",
19
+ committing: "committing",
20
+ complete: "complete",
21
+ };
package/src/types.ts ADDED
@@ -0,0 +1,249 @@
1
+ /**
2
+ * GLM Daemon - Core Types
3
+ *
4
+ * Autonomous AI daemon powered by GLM 4.7 with hooks, tools, and teammates.
5
+ * Based on Ralph Iterative's SLAM pattern (State → Loop → Action → Memory).
6
+ */
7
+
8
+ import type { Team } from "@ebowwa/teammates";
9
+
10
+ /**
11
+ * GLM Daemon state phases (SLAM pattern)
12
+ */
13
+ export const GLM_PHASES = {
14
+ planning: "planning",
15
+ executing: "executing",
16
+ paranoid: "paranoid",
17
+ reviewing: "reviewing",
18
+ fixing: "fixing",
19
+ committing: "committing",
20
+ complete: "complete",
21
+ } as const;
22
+
23
+ export type GLMPhase = keyof typeof GLM_PHASES;
24
+
25
+ /**
26
+ * GLM Daemon configuration
27
+ */
28
+ export interface GLMDaemonConfig {
29
+ /** Team name for multi-agent coordination */
30
+ teamName: string;
31
+
32
+ /** GLM model to use */
33
+ model?: string;
34
+
35
+ /** Working directory */
36
+ cwd: string;
37
+
38
+ /** Enable git worktree isolation */
39
+ enableWorktree?: boolean;
40
+
41
+ /** Enable automatic commits */
42
+ autoCommit?: boolean;
43
+
44
+ /** Enable automatic PR creation */
45
+ autoPR?: boolean;
46
+
47
+ /** Base branch for PRs */
48
+ baseBranch?: string;
49
+
50
+ /** Maximum iterations (0 = unlimited) */
51
+ maxIterations?: number;
52
+
53
+ /** Completion promise text */
54
+ completionPromise?: string;
55
+
56
+ /** Hooks configuration */
57
+ hooks?: GLMHooksConfig;
58
+
59
+ /** Tools configuration */
60
+ tools?: GLMToolsConfig;
61
+ }
62
+
63
+ /**
64
+ * GLM Daemon state (persisted to disk)
65
+ */
66
+ export interface GLMDaemonState {
67
+ /** Original prompt/task */
68
+ prompt: string;
69
+
70
+ /** Completion promise (when to stop) */
71
+ promise: string;
72
+
73
+ /** Current iteration */
74
+ iteration: number;
75
+
76
+ /** Maximum iterations */
77
+ maxIterations: number;
78
+
79
+ /** Start timestamp */
80
+ startTime: string;
81
+
82
+ /** Last update timestamp */
83
+ lastUpdate: string;
84
+
85
+ /** Token usage tracking */
86
+ tokens: {
87
+ totalInput: number;
88
+ totalOutput: number;
89
+ byIteration: Array<{
90
+ iteration: number;
91
+ input: number;
92
+ output: number;
93
+ }>;
94
+ };
95
+
96
+ /** Files changed in this session */
97
+ filesChanged: string[];
98
+
99
+ /** Working memory */
100
+ workMemory: {
101
+ completedFiles: string[];
102
+ fileChecksums: Record<string, string>;
103
+ };
104
+
105
+ /** SLAM state */
106
+ slam: {
107
+ enabled: boolean;
108
+ phase: GLMPhase;
109
+ state: {
110
+ currentTask: string;
111
+ beliefs: Record<string, unknown>;
112
+ goals: string[];
113
+ };
114
+ subtasks: GLMSubtask[];
115
+ currentSubtask: string | null;
116
+ completedSubtasks: string[];
117
+ memory: {
118
+ actionsTaken: string[];
119
+ outcomes: Record<string, unknown>;
120
+ patterns: Record<string, unknown>;
121
+ };
122
+ };
123
+
124
+ /** Git configuration */
125
+ git: {
126
+ enabled: boolean;
127
+ autoCommit: boolean;
128
+ autoPR: boolean;
129
+ baseBranch: string;
130
+ useWorktree: boolean;
131
+ branchName: string;
132
+ branchCreated: boolean;
133
+ currentCommit: string;
134
+ };
135
+
136
+ /** Machine info */
137
+ machine?: {
138
+ cpu: { count: number; model: string; tier: string };
139
+ memory: { total: number; free: number; tier: string };
140
+ disk: { total: number; available: number; tier: string };
141
+ platform: { os: string; arch: string; isContainer: boolean };
142
+ capacity: string;
143
+ score: number;
144
+ };
145
+ }
146
+
147
+ /**
148
+ * GLM Subtask (for SLAM coordination)
149
+ */
150
+ export interface GLMSubtask {
151
+ id: string;
152
+ title: string;
153
+ description: string;
154
+ status: "pending" | "in_progress" | "completed" | "blocked" | "failed";
155
+ assignedTo?: string;
156
+ dependencies?: string[];
157
+ result?: unknown;
158
+ }
159
+
160
+ /**
161
+ * GLM Hooks configuration
162
+ */
163
+ export interface GLMHooksConfig {
164
+ onSessionStart?: (state: GLMDaemonState) => Promise<void>;
165
+ onSessionEnd?: (state: GLMDaemonState) => Promise<void>;
166
+ onPreToolUse?: (tool: string, args: unknown) => Promise<boolean>;
167
+ onPostToolUse?: (tool: string, args: unknown, result: unknown) => Promise<void>;
168
+ onSubagentStart?: (subagentId: string) => Promise<void>;
169
+ onSubagentStop?: (subagentId: string, result: unknown) => Promise<void>;
170
+ onIterationStart?: (iteration: number) => Promise<void>;
171
+ onIterationEnd?: (iteration: number, result: unknown) => Promise<void>;
172
+ }
173
+
174
+ /**
175
+ * GLM Tools configuration
176
+ */
177
+ export interface GLMToolsConfig {
178
+ /** Enable MCP tool access */
179
+ enableMCP?: boolean;
180
+
181
+ /** Allowed tools (whitelist) */
182
+ allowedTools?: string[];
183
+
184
+ /** Blocked tools (blacklist) */
185
+ blockedTools?: string[];
186
+
187
+ /** Tool timeout in ms */
188
+ toolTimeout?: number;
189
+
190
+ /** Max retries for failed tools */
191
+ maxRetries?: number;
192
+ }
193
+
194
+ /**
195
+ * GLM Agent (individual GLM-powered agent)
196
+ */
197
+ export interface GLMAgentConfig {
198
+ /** Agent ID */
199
+ agentId: string;
200
+
201
+ /** Agent name */
202
+ name: string;
203
+
204
+ /** System prompt */
205
+ prompt: string;
206
+
207
+ /** Model to use */
208
+ model?: string;
209
+
210
+ /** Temperature (0-1) */
211
+ temperature?: number;
212
+
213
+ /** Max tokens */
214
+ maxTokens?: number;
215
+
216
+ /** Tools this agent can use */
217
+ tools?: string[];
218
+
219
+ /** Assigned subtasks */
220
+ assignedSubtasks?: string[];
221
+ }
222
+
223
+ /**
224
+ * GLM Tool execution result
225
+ */
226
+ export interface GLMToolResult {
227
+ success: boolean;
228
+ result?: unknown;
229
+ error?: string;
230
+ duration: number;
231
+ }
232
+
233
+ /**
234
+ * GLM Daemon status
235
+ */
236
+ export interface GLMDaemonStatus {
237
+ id: string;
238
+ status: "starting" | "running" | "complete" | "error" | "stopped";
239
+ phase: GLMPhase;
240
+ iteration: number;
241
+ prompt: string;
242
+ currentTask?: string;
243
+ totalSubtasks: number;
244
+ completedSubtasks: number;
245
+ startedAt: string;
246
+ lastUpdate: string;
247
+ processId?: number;
248
+ worktreePath?: string;
249
+ }
@@ -0,0 +1,195 @@
1
+ "use strict";
2
+ /**
3
+ * GLM Daemon - Worktree Manager
4
+ *
5
+ * Handles git worktree isolation for parallel task execution.
6
+ */
7
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
8
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
9
+ return new (P || (P = Promise))(function (resolve, reject) {
10
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
11
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
12
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
13
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
14
+ });
15
+ };
16
+ var __generator = (this && this.__generator) || function (thisArg, body) {
17
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
18
+ return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
19
+ function verb(n) { return function (v) { return step([n, v]); }; }
20
+ function step(op) {
21
+ if (f) throw new TypeError("Generator is already executing.");
22
+ while (g && (g = 0, op[0] && (_ = 0)), _) try {
23
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
24
+ if (y = 0, t) op = [op[0] & 2, t.value];
25
+ switch (op[0]) {
26
+ case 0: case 1: t = op; break;
27
+ case 4: _.label++; return { value: op[1], done: false };
28
+ case 5: _.label++; y = op[1]; op = [0]; continue;
29
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
30
+ default:
31
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
32
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
33
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
34
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
35
+ if (t[2]) _.ops.pop();
36
+ _.trys.pop(); continue;
37
+ }
38
+ op = body.call(thisArg, _);
39
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
40
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
41
+ }
42
+ };
43
+ Object.defineProperty(exports, "__esModule", { value: true });
44
+ exports.WorktreeManager = void 0;
45
+ var child_process_1 = require("child_process");
46
+ var util_1 = require("util");
47
+ var path_1 = require("path");
48
+ var execAsync = (0, util_1.promisify)(child_process_1.exec);
49
+ var WorktreeManager = /** @class */ (function () {
50
+ function WorktreeManager(config) {
51
+ this.worktreePath = null;
52
+ this.config = config;
53
+ }
54
+ /**
55
+ * Create a new worktree for isolation
56
+ */
57
+ WorktreeManager.prototype.createWorktree = function () {
58
+ return __awaiter(this, void 0, void 0, function () {
59
+ var timestamp, worktreeName;
60
+ return __generator(this, function (_a) {
61
+ switch (_a.label) {
62
+ case 0:
63
+ if (!this.config.enableWorktree) {
64
+ return [2 /*return*/, this.config.cwd];
65
+ }
66
+ timestamp = Date.now();
67
+ worktreeName = "glm-".concat(timestamp);
68
+ this.worktreePath = (0, path_1.join)(this.config.cwd, "worktrees", worktreeName);
69
+ // Create worktrees directory
70
+ return [4 /*yield*/, execAsync("mkdir -p ".concat((0, path_1.join)(this.config.cwd, "worktrees")))];
71
+ case 1:
72
+ // Create worktrees directory
73
+ _a.sent();
74
+ // Create worktree
75
+ return [4 /*yield*/, execAsync("git worktree add -b ".concat(worktreeName, " ").concat(this.worktreePath))];
76
+ case 2:
77
+ // Create worktree
78
+ _a.sent();
79
+ return [2 /*return*/, this.worktreePath];
80
+ }
81
+ });
82
+ });
83
+ };
84
+ /**
85
+ * Create a feature branch in the worktree
86
+ */
87
+ WorktreeManager.prototype.createBranch = function () {
88
+ return __awaiter(this, void 0, void 0, function () {
89
+ var branchName;
90
+ return __generator(this, function (_a) {
91
+ switch (_a.label) {
92
+ case 0:
93
+ if (!this.worktreePath) {
94
+ throw new Error("No worktree created");
95
+ }
96
+ branchName = "feat/glm-".concat(Date.now());
97
+ return [4 /*yield*/, execAsync("cd ".concat(this.worktreePath, " && git checkout -b ").concat(branchName))];
98
+ case 1:
99
+ _a.sent();
100
+ return [2 /*return*/, branchName];
101
+ }
102
+ });
103
+ });
104
+ };
105
+ /**
106
+ * Commit changes in the worktree
107
+ */
108
+ WorktreeManager.prototype.commitChanges = function (options) {
109
+ return __awaiter(this, void 0, void 0, function () {
110
+ var cwd, _i, _a, file, stdout;
111
+ return __generator(this, function (_b) {
112
+ switch (_b.label) {
113
+ case 0:
114
+ cwd = this.worktreePath || this.config.cwd;
115
+ _i = 0, _a = options.files;
116
+ _b.label = 1;
117
+ case 1:
118
+ if (!(_i < _a.length)) return [3 /*break*/, 4];
119
+ file = _a[_i];
120
+ return [4 /*yield*/, execAsync("cd ".concat(cwd, " && git add ").concat(file))];
121
+ case 2:
122
+ _b.sent();
123
+ _b.label = 3;
124
+ case 3:
125
+ _i++;
126
+ return [3 /*break*/, 1];
127
+ case 4: return [4 /*yield*/, execAsync("cd ".concat(cwd, " && git commit -m \"").concat(options.message, "\""))];
128
+ case 5:
129
+ stdout = (_b.sent()).stdout;
130
+ return [2 /*return*/, stdout.trim()];
131
+ }
132
+ });
133
+ });
134
+ };
135
+ /**
136
+ * Create a pull request
137
+ */
138
+ WorktreeManager.prototype.createPullRequest = function (options) {
139
+ return __awaiter(this, void 0, void 0, function () {
140
+ var cwd;
141
+ return __generator(this, function (_a) {
142
+ switch (_a.label) {
143
+ case 0:
144
+ cwd = this.worktreePath || this.config.cwd;
145
+ // Push branch
146
+ return [4 /*yield*/, execAsync("cd ".concat(cwd, " && git push -u origin HEAD"))];
147
+ case 1:
148
+ // Push branch
149
+ _a.sent();
150
+ // Create PR using gh CLI
151
+ return [4 /*yield*/, execAsync("cd ".concat(cwd, " && gh pr create --title \"").concat(options.title, "\" --body \"").concat(options.body, "\""))];
152
+ case 2:
153
+ // Create PR using gh CLI
154
+ _a.sent();
155
+ return [2 /*return*/];
156
+ }
157
+ });
158
+ });
159
+ };
160
+ /**
161
+ * Clean up worktree
162
+ */
163
+ WorktreeManager.prototype.cleanup = function () {
164
+ return __awaiter(this, void 0, void 0, function () {
165
+ return __generator(this, function (_a) {
166
+ switch (_a.label) {
167
+ case 0:
168
+ if (!this.worktreePath) {
169
+ return [2 /*return*/];
170
+ }
171
+ // Remove worktree
172
+ return [4 /*yield*/, execAsync("git worktree remove ".concat(this.worktreePath))];
173
+ case 1:
174
+ // Remove worktree
175
+ _a.sent();
176
+ // Delete directory
177
+ return [4 /*yield*/, execAsync("rm -rf ".concat(this.worktreePath))];
178
+ case 2:
179
+ // Delete directory
180
+ _a.sent();
181
+ this.worktreePath = null;
182
+ return [2 /*return*/];
183
+ }
184
+ });
185
+ });
186
+ };
187
+ /**
188
+ * Get worktree path
189
+ */
190
+ WorktreeManager.prototype.getPath = function () {
191
+ return this.worktreePath;
192
+ };
193
+ return WorktreeManager;
194
+ }());
195
+ exports.WorktreeManager = WorktreeManager;