@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.
- package/README.md +264 -0
- package/dist/agent.d.ts +37 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +97 -0
- package/dist/agent.js.map +1 -0
- package/dist/daemon.d.ts +91 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +449 -0
- package/dist/daemon.js.map +1 -0
- package/dist/hooks.d.ts +34 -0
- package/dist/hooks.d.ts.map +1 -0
- package/dist/hooks.js +82 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/index.js.map +1 -0
- package/dist/state.d.ts +31 -0
- package/dist/state.d.ts.map +1 -0
- package/dist/state.js +67 -0
- package/dist/state.js.map +1 -0
- package/dist/tools.d.ts +42 -0
- package/dist/tools.d.ts.map +1 -0
- package/dist/tools.js +110 -0
- package/dist/tools.js.map +1 -0
- package/dist/types.d.ts +222 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +19 -0
- package/dist/types.js.map +1 -0
- package/dist/worktree.d.ts +42 -0
- package/dist/worktree.d.ts.map +1 -0
- package/dist/worktree.js +86 -0
- package/dist/worktree.js.map +1 -0
- package/package.json +70 -0
- package/src/agent.js +166 -0
- package/src/agent.ts +110 -0
- package/src/daemon.js +591 -0
- package/src/daemon.ts +529 -0
- package/src/hooks.js +145 -0
- package/src/hooks.ts +94 -0
- package/src/index.js +105 -0
- package/src/index.ts +43 -0
- package/src/state.js +168 -0
- package/src/state.ts +77 -0
- package/src/tools.js +192 -0
- package/src/tools.ts +134 -0
- package/src/types.js +21 -0
- package/src/types.ts +249 -0
- package/src/worktree.js +195 -0
- 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
|
+
}
|
package/src/worktree.js
ADDED
|
@@ -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;
|