nightshift-mcp 1.0.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 +670 -0
- package/dist/agent-spawner.d.ts +55 -0
- package/dist/agent-spawner.d.ts.map +1 -0
- package/dist/agent-spawner.js +468 -0
- package/dist/agent-spawner.js.map +1 -0
- package/dist/chat-manager.d.ts +72 -0
- package/dist/chat-manager.d.ts.map +1 -0
- package/dist/chat-manager.js +331 -0
- package/dist/chat-manager.js.map +1 -0
- package/dist/daemon.d.ts +65 -0
- package/dist/daemon.d.ts.map +1 -0
- package/dist/daemon.js +563 -0
- package/dist/daemon.js.map +1 -0
- package/dist/file-lock.d.ts +41 -0
- package/dist/file-lock.d.ts.map +1 -0
- package/dist/file-lock.js +157 -0
- package/dist/file-lock.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2433 -0
- package/dist/index.js.map +1 -0
- package/dist/ralph-manager.d.ts +148 -0
- package/dist/ralph-manager.d.ts.map +1 -0
- package/dist/ralph-manager.js +399 -0
- package/dist/ralph-manager.js.map +1 -0
- package/dist/tool-registry.d.ts +130 -0
- package/dist/tool-registry.d.ts.map +1 -0
- package/dist/tool-registry.js +280 -0
- package/dist/tool-registry.js.map +1 -0
- package/dist/tools/agents.d.ts +7 -0
- package/dist/tools/agents.d.ts.map +1 -0
- package/dist/tools/agents.js +366 -0
- package/dist/tools/agents.js.map +1 -0
- package/dist/tools/bugs.d.ts +6 -0
- package/dist/tools/bugs.d.ts.map +1 -0
- package/dist/tools/bugs.js +184 -0
- package/dist/tools/bugs.js.map +1 -0
- package/dist/tools/chat.d.ts +10 -0
- package/dist/tools/chat.d.ts.map +1 -0
- package/dist/tools/chat.js +287 -0
- package/dist/tools/chat.js.map +1 -0
- package/dist/tools/index.d.ts +33 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +51 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/prd.d.ts +8 -0
- package/dist/tools/prd.d.ts.map +1 -0
- package/dist/tools/prd.js +275 -0
- package/dist/tools/prd.js.map +1 -0
- package/dist/tools/progress.d.ts +5 -0
- package/dist/tools/progress.d.ts.map +1 -0
- package/dist/tools/progress.js +81 -0
- package/dist/tools/progress.js.map +1 -0
- package/dist/tools/savepoints.d.ts +5 -0
- package/dist/tools/savepoints.d.ts.map +1 -0
- package/dist/tools/savepoints.js +100 -0
- package/dist/tools/savepoints.js.map +1 -0
- package/dist/tools/utility.d.ts +4 -0
- package/dist/tools/utility.d.ts.map +1 -0
- package/dist/tools/utility.js +375 -0
- package/dist/tools/utility.js.map +1 -0
- package/dist/tools/workflow.d.ts +10 -0
- package/dist/tools/workflow.d.ts.map +1 -0
- package/dist/tools/workflow.js +321 -0
- package/dist/tools/workflow.js.map +1 -0
- package/dist/types.d.ts +105 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/workflow-manager.d.ts +154 -0
- package/dist/workflow-manager.d.ts.map +1 -0
- package/dist/workflow-manager.js +356 -0
- package/dist/workflow-manager.js.map +1 -0
- package/package.json +48 -0
package/dist/daemon.js
ADDED
|
@@ -0,0 +1,563 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* NightShift Daemon
|
|
4
|
+
*
|
|
5
|
+
* Event-driven orchestrator with polling fallback.
|
|
6
|
+
* Manages agent lifecycle, story assignments, and failover handling.
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import { RalphManager } from "./ralph-manager.js";
|
|
11
|
+
import { ChatManager } from "./chat-manager.js";
|
|
12
|
+
import { WorkflowManager } from "./workflow-manager.js";
|
|
13
|
+
import { spawnAgentBackground, getAvailableAgents, } from "./agent-spawner.js";
|
|
14
|
+
// ============================================
|
|
15
|
+
// Daemon Class
|
|
16
|
+
// ============================================
|
|
17
|
+
export class NightShiftDaemon {
|
|
18
|
+
config;
|
|
19
|
+
ralph;
|
|
20
|
+
chat;
|
|
21
|
+
workflow;
|
|
22
|
+
// State
|
|
23
|
+
running = false;
|
|
24
|
+
activeAgents = new Map();
|
|
25
|
+
storyStates = new Map();
|
|
26
|
+
availableAgents = [];
|
|
27
|
+
agentIndex = 0; // Round-robin
|
|
28
|
+
// File watchers
|
|
29
|
+
prdWatcher = null;
|
|
30
|
+
chatWatcher = null;
|
|
31
|
+
watchersHealthy = true;
|
|
32
|
+
// Timers
|
|
33
|
+
healthCheckTimer = null;
|
|
34
|
+
debounceTimers = new Map();
|
|
35
|
+
// Singleton lock
|
|
36
|
+
lockFile;
|
|
37
|
+
lockFd = null;
|
|
38
|
+
constructor(config) {
|
|
39
|
+
this.config = {
|
|
40
|
+
projectPath: config.projectPath,
|
|
41
|
+
healthCheckInterval: config.healthCheckInterval ?? 2 * 60 * 1000, // 2 minutes
|
|
42
|
+
debounceInterval: config.debounceInterval ?? 500, // 500ms
|
|
43
|
+
stuckTimeout: config.stuckTimeout ?? 15 * 60 * 1000, // 15 minutes
|
|
44
|
+
maxConcurrentAgents: config.maxConcurrentAgents ?? 3,
|
|
45
|
+
maxRetries: config.maxRetries ?? 3,
|
|
46
|
+
agents: config.agents ?? ["claude", "codex", "gemini", "vibe"],
|
|
47
|
+
verbose: config.verbose ?? false,
|
|
48
|
+
dryRun: config.dryRun ?? false,
|
|
49
|
+
};
|
|
50
|
+
this.ralph = new RalphManager(this.config.projectPath);
|
|
51
|
+
this.chat = new ChatManager(this.config.projectPath);
|
|
52
|
+
this.workflow = new WorkflowManager(this.config.projectPath);
|
|
53
|
+
this.lockFile = path.join(this.config.projectPath, ".robot-chat", "daemon.lock");
|
|
54
|
+
}
|
|
55
|
+
// ============================================
|
|
56
|
+
// Logging
|
|
57
|
+
// ============================================
|
|
58
|
+
log(level, message, data) {
|
|
59
|
+
if (level === "debug" && !this.config.verbose)
|
|
60
|
+
return;
|
|
61
|
+
const timestamp = new Date().toISOString();
|
|
62
|
+
const prefix = {
|
|
63
|
+
info: "ℹ️ ",
|
|
64
|
+
warn: "⚠️ ",
|
|
65
|
+
error: "❌",
|
|
66
|
+
debug: "🔍",
|
|
67
|
+
}[level];
|
|
68
|
+
const logLine = `[${timestamp}] ${prefix} ${message}`;
|
|
69
|
+
if (level === "error") {
|
|
70
|
+
console.error(logLine, data ?? "");
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
console.log(logLine, data ? JSON.stringify(data) : "");
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
// ============================================
|
|
77
|
+
// Singleton Lock
|
|
78
|
+
// ============================================
|
|
79
|
+
acquireLock() {
|
|
80
|
+
try {
|
|
81
|
+
const lockDir = path.dirname(this.lockFile);
|
|
82
|
+
if (!fs.existsSync(lockDir)) {
|
|
83
|
+
fs.mkdirSync(lockDir, { recursive: true });
|
|
84
|
+
}
|
|
85
|
+
// Try to open exclusively
|
|
86
|
+
this.lockFd = fs.openSync(this.lockFile, "wx");
|
|
87
|
+
fs.writeFileSync(this.lockFile, String(process.pid));
|
|
88
|
+
// Clean up on exit
|
|
89
|
+
process.on("exit", () => this.releaseLock());
|
|
90
|
+
process.on("SIGINT", () => { this.releaseLock(); process.exit(0); });
|
|
91
|
+
process.on("SIGTERM", () => { this.releaseLock(); process.exit(0); });
|
|
92
|
+
return true;
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
if (err.code === "EEXIST") {
|
|
96
|
+
// Check if the process is still running
|
|
97
|
+
try {
|
|
98
|
+
const pid = parseInt(fs.readFileSync(this.lockFile, "utf-8").trim());
|
|
99
|
+
process.kill(pid, 0); // Check if process exists
|
|
100
|
+
this.log("error", `Another daemon is running (PID: ${pid})`);
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
catch {
|
|
104
|
+
// Process doesn't exist, remove stale lock
|
|
105
|
+
fs.unlinkSync(this.lockFile);
|
|
106
|
+
return this.acquireLock();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw err;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
releaseLock() {
|
|
113
|
+
try {
|
|
114
|
+
if (this.lockFd !== null) {
|
|
115
|
+
fs.closeSync(this.lockFd);
|
|
116
|
+
this.lockFd = null;
|
|
117
|
+
}
|
|
118
|
+
if (fs.existsSync(this.lockFile)) {
|
|
119
|
+
fs.unlinkSync(this.lockFile);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
catch {
|
|
123
|
+
// Ignore cleanup errors
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
// ============================================
|
|
127
|
+
// File Watchers
|
|
128
|
+
// ============================================
|
|
129
|
+
startWatchers() {
|
|
130
|
+
const prdPath = path.join(this.config.projectPath, "prd.json");
|
|
131
|
+
const chatPath = path.join(this.config.projectPath, ".robot-chat", "chat.txt");
|
|
132
|
+
try {
|
|
133
|
+
// Watch prd.json for story changes
|
|
134
|
+
if (fs.existsSync(prdPath)) {
|
|
135
|
+
this.prdWatcher = fs.watch(prdPath, (event) => {
|
|
136
|
+
if (event === "change") {
|
|
137
|
+
this.debounce("prd", () => this.onPrdChanged());
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
this.log("info", "Watching prd.json");
|
|
141
|
+
}
|
|
142
|
+
// Watch chat.txt for failovers and completions
|
|
143
|
+
if (fs.existsSync(chatPath)) {
|
|
144
|
+
this.chatWatcher = fs.watch(chatPath, (event) => {
|
|
145
|
+
if (event === "change") {
|
|
146
|
+
this.debounce("chat", () => this.onChatChanged());
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
this.log("info", "Watching chat.txt");
|
|
150
|
+
}
|
|
151
|
+
this.watchersHealthy = true;
|
|
152
|
+
}
|
|
153
|
+
catch (err) {
|
|
154
|
+
this.log("error", "Failed to start file watchers", { error: String(err) });
|
|
155
|
+
this.watchersHealthy = false;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
stopWatchers() {
|
|
159
|
+
if (this.prdWatcher) {
|
|
160
|
+
this.prdWatcher.close();
|
|
161
|
+
this.prdWatcher = null;
|
|
162
|
+
}
|
|
163
|
+
if (this.chatWatcher) {
|
|
164
|
+
this.chatWatcher.close();
|
|
165
|
+
this.chatWatcher = null;
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
restartWatchers() {
|
|
169
|
+
this.log("warn", "Restarting file watchers");
|
|
170
|
+
this.stopWatchers();
|
|
171
|
+
this.startWatchers();
|
|
172
|
+
}
|
|
173
|
+
debounce(key, fn) {
|
|
174
|
+
const existing = this.debounceTimers.get(key);
|
|
175
|
+
if (existing) {
|
|
176
|
+
clearTimeout(existing);
|
|
177
|
+
}
|
|
178
|
+
const timer = setTimeout(() => {
|
|
179
|
+
this.debounceTimers.delete(key);
|
|
180
|
+
fn();
|
|
181
|
+
}, this.config.debounceInterval);
|
|
182
|
+
this.debounceTimers.set(key, timer);
|
|
183
|
+
}
|
|
184
|
+
// ============================================
|
|
185
|
+
// Event Handlers
|
|
186
|
+
// ============================================
|
|
187
|
+
async onPrdChanged() {
|
|
188
|
+
this.log("debug", "PRD changed");
|
|
189
|
+
await this.reconcile();
|
|
190
|
+
}
|
|
191
|
+
async onChatChanged() {
|
|
192
|
+
this.log("debug", "Chat changed");
|
|
193
|
+
// Check for failovers
|
|
194
|
+
const failovers = this.chat.findUnclaimedFailovers();
|
|
195
|
+
for (const failover of failovers) {
|
|
196
|
+
this.log("info", `Found unclaimed failover from ${failover.requestingAgent}`);
|
|
197
|
+
await this.handleFailover(failover);
|
|
198
|
+
}
|
|
199
|
+
// Update agent activity timestamps
|
|
200
|
+
const recentMessages = this.chat.readMessages({ limit: 10 });
|
|
201
|
+
for (const msg of recentMessages) {
|
|
202
|
+
// Find agent process and update lastActivity
|
|
203
|
+
for (const [storyId, proc] of this.activeAgents) {
|
|
204
|
+
if (msg.content.includes(storyId)) {
|
|
205
|
+
proc.lastActivity = Date.now();
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
await this.reconcile();
|
|
210
|
+
}
|
|
211
|
+
async handleFailover(failover) {
|
|
212
|
+
if (this.config.dryRun) {
|
|
213
|
+
this.log("info", `[DRY RUN] Would claim failover from ${failover.requestingAgent}`);
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
// Extract story ID from failover message if possible
|
|
217
|
+
const storyMatch = failover.message.content.match(/US-\d+/);
|
|
218
|
+
const storyId = storyMatch?.[0];
|
|
219
|
+
if (storyId) {
|
|
220
|
+
// Remove from active agents if tracked
|
|
221
|
+
this.activeAgents.delete(storyId);
|
|
222
|
+
}
|
|
223
|
+
// Claim the failover
|
|
224
|
+
const nextAgent = this.getNextAgent();
|
|
225
|
+
if (nextAgent) {
|
|
226
|
+
await this.chat.claimFailover(nextAgent, failover.requestingAgent, failover.task);
|
|
227
|
+
this.log("info", `${nextAgent} claimed failover from ${failover.requestingAgent}`);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
// ============================================
|
|
231
|
+
// Reconciliation Loop
|
|
232
|
+
// ============================================
|
|
233
|
+
async reconcile() {
|
|
234
|
+
if (!this.running)
|
|
235
|
+
return;
|
|
236
|
+
this.log("debug", "Reconciling state");
|
|
237
|
+
// Get current state
|
|
238
|
+
const prd = this.ralph.readPRD();
|
|
239
|
+
if (!prd) {
|
|
240
|
+
this.log("warn", "No prd.json found");
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
const incomplete = prd.userStories.filter(s => !s.passes);
|
|
244
|
+
const activeCount = this.activeAgents.size;
|
|
245
|
+
// Check if all complete
|
|
246
|
+
if (incomplete.length === 0) {
|
|
247
|
+
this.log("info", "🎉 All stories complete!");
|
|
248
|
+
await this.shutdown();
|
|
249
|
+
return;
|
|
250
|
+
}
|
|
251
|
+
// Find orphaned stories (incomplete but not assigned)
|
|
252
|
+
const assignedIds = new Set(this.activeAgents.keys());
|
|
253
|
+
const orphaned = incomplete.filter(s => !assignedIds.has(s.id) &&
|
|
254
|
+
!this.isQuarantined(s.id));
|
|
255
|
+
// Spawn agents for orphaned stories up to concurrency limit
|
|
256
|
+
const slotsAvailable = this.config.maxConcurrentAgents - activeCount;
|
|
257
|
+
const toSpawn = orphaned.slice(0, slotsAvailable);
|
|
258
|
+
for (const story of toSpawn) {
|
|
259
|
+
await this.spawnAgentForStory(story.id);
|
|
260
|
+
}
|
|
261
|
+
// Log status
|
|
262
|
+
this.log("info", `Status: ${incomplete.length} incomplete, ${activeCount} active, ${orphaned.length} orphaned`);
|
|
263
|
+
}
|
|
264
|
+
// ============================================
|
|
265
|
+
// Agent Management
|
|
266
|
+
// ============================================
|
|
267
|
+
getNextAgent() {
|
|
268
|
+
if (this.availableAgents.length === 0)
|
|
269
|
+
return null;
|
|
270
|
+
const agent = this.availableAgents[this.agentIndex % this.availableAgents.length];
|
|
271
|
+
this.agentIndex++;
|
|
272
|
+
return agent;
|
|
273
|
+
}
|
|
274
|
+
async spawnAgentForStory(storyId) {
|
|
275
|
+
const agent = this.getNextAgent();
|
|
276
|
+
if (!agent) {
|
|
277
|
+
this.log("warn", "No agents available");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
if (this.config.dryRun) {
|
|
281
|
+
this.log("info", `[DRY RUN] Would spawn ${agent} for ${storyId}`);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
this.log("info", `Spawning ${agent} for ${storyId}`);
|
|
285
|
+
// Get story details
|
|
286
|
+
const story = this.ralph.getStory(storyId);
|
|
287
|
+
if (!story) {
|
|
288
|
+
this.log("error", `Story ${storyId} not found`);
|
|
289
|
+
return;
|
|
290
|
+
}
|
|
291
|
+
// Build prompt
|
|
292
|
+
const prompt = this.buildAgentPrompt(story);
|
|
293
|
+
// Spawn in background
|
|
294
|
+
const result = spawnAgentBackground({
|
|
295
|
+
agent,
|
|
296
|
+
prompt,
|
|
297
|
+
projectPath: this.config.projectPath,
|
|
298
|
+
});
|
|
299
|
+
// Track the agent
|
|
300
|
+
this.activeAgents.set(storyId, {
|
|
301
|
+
agent,
|
|
302
|
+
storyId,
|
|
303
|
+
pid: result.pid,
|
|
304
|
+
startTime: Date.now(),
|
|
305
|
+
lastActivity: Date.now(),
|
|
306
|
+
outputFile: result.outputFile,
|
|
307
|
+
});
|
|
308
|
+
// Post to chat
|
|
309
|
+
this.chat.writeMessage({
|
|
310
|
+
agent: "NightShift",
|
|
311
|
+
type: "INFO",
|
|
312
|
+
content: `Spawned ${agent} to work on ${storyId}: ${story.title}`,
|
|
313
|
+
});
|
|
314
|
+
// Monitor the agent process
|
|
315
|
+
this.monitorAgent(storyId, result.pid, result.outputFile);
|
|
316
|
+
}
|
|
317
|
+
buildAgentPrompt(story) {
|
|
318
|
+
const progress = this.ralph.readProgress();
|
|
319
|
+
return `You are working on a NightShift MCP project.
|
|
320
|
+
|
|
321
|
+
## Your Task
|
|
322
|
+
Story: ${story.id} - ${story.title}
|
|
323
|
+
Description: ${story.description}
|
|
324
|
+
|
|
325
|
+
Acceptance Criteria:
|
|
326
|
+
${story.acceptanceCriteria.map((c) => `- ${c}`).join("\n")}
|
|
327
|
+
|
|
328
|
+
## Instructions
|
|
329
|
+
1. Read CLAUDE.md for project context and nightshift tools
|
|
330
|
+
2. Use claim_story to claim ${story.id}
|
|
331
|
+
3. Implement the story
|
|
332
|
+
4. Run quality checks (typecheck, lint, test)
|
|
333
|
+
5. Commit your changes
|
|
334
|
+
6. Use complete_story when done
|
|
335
|
+
|
|
336
|
+
## Progress Context
|
|
337
|
+
${progress ? progress.substring(0, 2000) : "No progress file yet."}
|
|
338
|
+
|
|
339
|
+
## Important
|
|
340
|
+
- If you hit rate limits or context limits, post FAILOVER_NEEDED
|
|
341
|
+
- Post STATUS_UPDATE messages periodically
|
|
342
|
+
- Focus only on this story, don't work on others
|
|
343
|
+
`;
|
|
344
|
+
}
|
|
345
|
+
monitorAgent(storyId, pid, outputFile) {
|
|
346
|
+
if (!pid)
|
|
347
|
+
return;
|
|
348
|
+
// Check periodically if process is still running
|
|
349
|
+
const checkInterval = setInterval(() => {
|
|
350
|
+
try {
|
|
351
|
+
process.kill(pid, 0); // Check if process exists
|
|
352
|
+
}
|
|
353
|
+
catch {
|
|
354
|
+
// Process exited
|
|
355
|
+
clearInterval(checkInterval);
|
|
356
|
+
this.onAgentExit(storyId, pid);
|
|
357
|
+
}
|
|
358
|
+
}, 10000); // Check every 10 seconds
|
|
359
|
+
}
|
|
360
|
+
async onAgentExit(storyId, pid) {
|
|
361
|
+
const agentProc = this.activeAgents.get(storyId);
|
|
362
|
+
if (!agentProc)
|
|
363
|
+
return;
|
|
364
|
+
this.log("info", `Agent ${agentProc.agent} (PID: ${pid}) exited for ${storyId}`);
|
|
365
|
+
// Check if story is complete
|
|
366
|
+
const story = this.ralph.getStory(storyId);
|
|
367
|
+
if (story?.passes) {
|
|
368
|
+
this.log("info", `✅ ${storyId} completed successfully`);
|
|
369
|
+
this.activeAgents.delete(storyId);
|
|
370
|
+
}
|
|
371
|
+
else {
|
|
372
|
+
// Agent exited without completing - might need retry
|
|
373
|
+
this.incrementRetry(storyId);
|
|
374
|
+
this.activeAgents.delete(storyId);
|
|
375
|
+
if (this.isQuarantined(storyId)) {
|
|
376
|
+
this.log("warn", `${storyId} quarantined after ${this.config.maxRetries} failures`);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
// Reconcile to pick up more work
|
|
380
|
+
await this.reconcile();
|
|
381
|
+
}
|
|
382
|
+
incrementRetry(storyId) {
|
|
383
|
+
const state = this.storyStates.get(storyId) ?? {
|
|
384
|
+
id: storyId,
|
|
385
|
+
retryCount: 0,
|
|
386
|
+
quarantined: false,
|
|
387
|
+
};
|
|
388
|
+
state.retryCount++;
|
|
389
|
+
if (state.retryCount >= this.config.maxRetries) {
|
|
390
|
+
state.quarantined = true;
|
|
391
|
+
}
|
|
392
|
+
this.storyStates.set(storyId, state);
|
|
393
|
+
}
|
|
394
|
+
isQuarantined(storyId) {
|
|
395
|
+
return this.storyStates.get(storyId)?.quarantined ?? false;
|
|
396
|
+
}
|
|
397
|
+
// ============================================
|
|
398
|
+
// Health Check (Polling Fallback)
|
|
399
|
+
// ============================================
|
|
400
|
+
startHealthCheck() {
|
|
401
|
+
this.healthCheckTimer = setInterval(() => this.healthCheck(), this.config.healthCheckInterval);
|
|
402
|
+
// Run immediately on start
|
|
403
|
+
this.healthCheck();
|
|
404
|
+
}
|
|
405
|
+
stopHealthCheck() {
|
|
406
|
+
if (this.healthCheckTimer) {
|
|
407
|
+
clearInterval(this.healthCheckTimer);
|
|
408
|
+
this.healthCheckTimer = null;
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
async healthCheck() {
|
|
412
|
+
this.log("debug", "Running health check");
|
|
413
|
+
// 1. Check for stuck agents
|
|
414
|
+
const now = Date.now();
|
|
415
|
+
for (const [storyId, proc] of this.activeAgents) {
|
|
416
|
+
const inactiveTime = now - proc.lastActivity;
|
|
417
|
+
if (inactiveTime > this.config.stuckTimeout) {
|
|
418
|
+
this.log("warn", `Agent ${proc.agent} stuck on ${storyId} (inactive ${Math.round(inactiveTime / 60000)}min)`);
|
|
419
|
+
// Kill the stuck process
|
|
420
|
+
if (proc.pid) {
|
|
421
|
+
try {
|
|
422
|
+
process.kill(proc.pid, "SIGTERM");
|
|
423
|
+
}
|
|
424
|
+
catch {
|
|
425
|
+
// Process may already be dead
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
this.activeAgents.delete(storyId);
|
|
429
|
+
this.incrementRetry(storyId);
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
// 2. Check for unclaimed failovers
|
|
433
|
+
const failovers = this.chat.findUnclaimedFailovers();
|
|
434
|
+
if (failovers.length > 0) {
|
|
435
|
+
this.log("info", `Health check found ${failovers.length} unclaimed failovers`);
|
|
436
|
+
for (const failover of failovers) {
|
|
437
|
+
await this.handleFailover(failover);
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
// 3. Restart watchers if needed
|
|
441
|
+
if (!this.watchersHealthy) {
|
|
442
|
+
this.restartWatchers();
|
|
443
|
+
}
|
|
444
|
+
// 4. Reconcile state
|
|
445
|
+
await this.reconcile();
|
|
446
|
+
}
|
|
447
|
+
// ============================================
|
|
448
|
+
// Lifecycle
|
|
449
|
+
// ============================================
|
|
450
|
+
async start() {
|
|
451
|
+
this.log("info", "Starting NightShift daemon");
|
|
452
|
+
// Acquire singleton lock
|
|
453
|
+
if (!this.acquireLock()) {
|
|
454
|
+
this.log("error", "Could not acquire lock - another daemon may be running");
|
|
455
|
+
process.exit(1);
|
|
456
|
+
}
|
|
457
|
+
// Check available agents
|
|
458
|
+
this.availableAgents = await getAvailableAgents();
|
|
459
|
+
const configuredAgents = this.config.agents.filter(a => this.availableAgents.includes(a));
|
|
460
|
+
if (configuredAgents.length === 0) {
|
|
461
|
+
this.log("error", "No configured agents are available");
|
|
462
|
+
process.exit(1);
|
|
463
|
+
}
|
|
464
|
+
this.availableAgents = configuredAgents;
|
|
465
|
+
this.log("info", `Available agents: ${this.availableAgents.join(", ")}`);
|
|
466
|
+
this.running = true;
|
|
467
|
+
// Start event watchers (primary)
|
|
468
|
+
this.startWatchers();
|
|
469
|
+
// Start health check (fallback)
|
|
470
|
+
this.startHealthCheck();
|
|
471
|
+
this.log("info", "Daemon started successfully");
|
|
472
|
+
this.log("info", `Health check interval: ${this.config.healthCheckInterval / 1000}s`);
|
|
473
|
+
this.log("info", `Max concurrent agents: ${this.config.maxConcurrentAgents}`);
|
|
474
|
+
// Initial reconciliation
|
|
475
|
+
await this.reconcile();
|
|
476
|
+
}
|
|
477
|
+
async shutdown() {
|
|
478
|
+
this.log("info", "Shutting down daemon");
|
|
479
|
+
this.running = false;
|
|
480
|
+
// Stop timers
|
|
481
|
+
this.stopHealthCheck();
|
|
482
|
+
for (const timer of this.debounceTimers.values()) {
|
|
483
|
+
clearTimeout(timer);
|
|
484
|
+
}
|
|
485
|
+
this.debounceTimers.clear();
|
|
486
|
+
// Stop watchers
|
|
487
|
+
this.stopWatchers();
|
|
488
|
+
// Release lock
|
|
489
|
+
this.releaseLock();
|
|
490
|
+
this.log("info", "Daemon stopped");
|
|
491
|
+
process.exit(0);
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
// ============================================
|
|
495
|
+
// CLI Entry Point
|
|
496
|
+
// ============================================
|
|
497
|
+
async function main() {
|
|
498
|
+
const args = process.argv.slice(2);
|
|
499
|
+
// Parse arguments
|
|
500
|
+
const projectPath = process.env.ROBOT_CHAT_PROJECT_PATH || process.cwd();
|
|
501
|
+
let verbose = false;
|
|
502
|
+
let dryRun = false;
|
|
503
|
+
let healthCheckInterval = 2 * 60 * 1000;
|
|
504
|
+
let maxConcurrentAgents = 3;
|
|
505
|
+
for (let i = 0; i < args.length; i++) {
|
|
506
|
+
switch (args[i]) {
|
|
507
|
+
case "--verbose":
|
|
508
|
+
case "-v":
|
|
509
|
+
verbose = true;
|
|
510
|
+
break;
|
|
511
|
+
case "--dry-run":
|
|
512
|
+
dryRun = true;
|
|
513
|
+
break;
|
|
514
|
+
case "--health-check":
|
|
515
|
+
const interval = args[++i];
|
|
516
|
+
if (interval?.endsWith("m")) {
|
|
517
|
+
healthCheckInterval = parseInt(interval) * 60 * 1000;
|
|
518
|
+
}
|
|
519
|
+
else if (interval?.endsWith("s")) {
|
|
520
|
+
healthCheckInterval = parseInt(interval) * 1000;
|
|
521
|
+
}
|
|
522
|
+
break;
|
|
523
|
+
case "--max-agents":
|
|
524
|
+
maxConcurrentAgents = parseInt(args[++i]) || 3;
|
|
525
|
+
break;
|
|
526
|
+
case "--help":
|
|
527
|
+
case "-h":
|
|
528
|
+
console.log(`
|
|
529
|
+
NightShift Daemon - Event-driven multi-agent orchestrator
|
|
530
|
+
|
|
531
|
+
Usage: nightshift-daemon [options]
|
|
532
|
+
|
|
533
|
+
Options:
|
|
534
|
+
--verbose, -v Enable verbose logging
|
|
535
|
+
--dry-run Show what would happen without spawning agents
|
|
536
|
+
--health-check <N> Health check interval (e.g., "2m", "30s") [default: 2m]
|
|
537
|
+
--max-agents <N> Maximum concurrent agents [default: 3]
|
|
538
|
+
--help, -h Show this help
|
|
539
|
+
|
|
540
|
+
Environment:
|
|
541
|
+
ROBOT_CHAT_PROJECT_PATH Project directory [default: cwd]
|
|
542
|
+
`);
|
|
543
|
+
process.exit(0);
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
const daemon = new NightShiftDaemon({
|
|
547
|
+
projectPath,
|
|
548
|
+
verbose,
|
|
549
|
+
dryRun,
|
|
550
|
+
healthCheckInterval,
|
|
551
|
+
maxConcurrentAgents,
|
|
552
|
+
});
|
|
553
|
+
await daemon.start();
|
|
554
|
+
}
|
|
555
|
+
// Run if executed directly
|
|
556
|
+
const isMain = import.meta.url === `file://${process.argv[1]}`;
|
|
557
|
+
if (isMain) {
|
|
558
|
+
main().catch((err) => {
|
|
559
|
+
console.error("Fatal error:", err);
|
|
560
|
+
process.exit(1);
|
|
561
|
+
});
|
|
562
|
+
}
|
|
563
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Options for file operations with locking
|
|
3
|
+
*/
|
|
4
|
+
export interface LockOptions {
|
|
5
|
+
retries?: number;
|
|
6
|
+
stale?: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Execute a function with exclusive file lock
|
|
10
|
+
*/
|
|
11
|
+
export declare function withFileLock<T>(filePath: string, fn: () => T | Promise<T>, options?: LockOptions): Promise<T>;
|
|
12
|
+
/**
|
|
13
|
+
* Read a file with locking
|
|
14
|
+
*/
|
|
15
|
+
export declare function readFileWithLock(filePath: string, options?: LockOptions): Promise<string>;
|
|
16
|
+
/**
|
|
17
|
+
* Write a file with locking
|
|
18
|
+
*/
|
|
19
|
+
export declare function writeFileWithLock(filePath: string, content: string, options?: LockOptions): Promise<void>;
|
|
20
|
+
/**
|
|
21
|
+
* Append to a file with locking
|
|
22
|
+
*/
|
|
23
|
+
export declare function appendFileWithLock(filePath: string, content: string, options?: LockOptions): Promise<void>;
|
|
24
|
+
/**
|
|
25
|
+
* Read and parse JSON with locking, with safe fallback on parse error
|
|
26
|
+
*/
|
|
27
|
+
export declare function readJsonWithLock<T>(filePath: string, defaultValue: T, options?: LockOptions): Promise<T>;
|
|
28
|
+
/**
|
|
29
|
+
* Write JSON with locking
|
|
30
|
+
*/
|
|
31
|
+
export declare function writeJsonWithLock<T>(filePath: string, data: T, options?: LockOptions): Promise<void>;
|
|
32
|
+
/**
|
|
33
|
+
* Atomic read-modify-write operation with locking
|
|
34
|
+
*/
|
|
35
|
+
export declare function modifyJsonWithLock<T>(filePath: string, modifier: (current: T | null) => T, options?: LockOptions): Promise<T>;
|
|
36
|
+
/**
|
|
37
|
+
* Escape shell string to prevent command injection
|
|
38
|
+
* Escapes single quotes, backticks, and $() constructs
|
|
39
|
+
*/
|
|
40
|
+
export declare function escapeShellString(str: string): string;
|
|
41
|
+
//# sourceMappingURL=file-lock.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-lock.d.ts","sourceRoot":"","sources":["../src/file-lock.ts"],"names":[],"mappings":"AAIA;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAOD;;GAEG;AACH,wBAAsB,YAAY,CAAC,CAAC,EAClC,QAAQ,EAAE,MAAM,EAChB,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,EACxB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,CAAC,CAAC,CA+BZ;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CACpC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,MAAM,CAAC,CAWjB;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;GAEG;AACH,wBAAsB,gBAAgB,CAAC,CAAC,EACtC,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,CAAC,EACf,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,CAAC,CAAC,CAuBZ;AAED;;GAEG;AACH,wBAAsB,iBAAiB,CAAC,CAAC,EACvC,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,CAAC,EACP,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAYf;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,CAAC,EACxC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,IAAI,KAAK,CAAC,EAClC,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,CAAC,CAAC,CA+BZ;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAiBrD"}
|