nightshift-mcp 1.1.1 → 2.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 +979 -971
- package/dist/agent-spawner.js +85 -85
- package/dist/chat-manager.js +8 -8
- package/dist/cli.js +32 -32
- package/dist/daemon-manager.js +69 -69
- package/dist/daemon.d.ts +21 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +247 -47
- package/dist/daemon.js.map +1 -1
- package/dist/database.d.ts +139 -0
- package/dist/database.d.ts.map +1 -0
- package/dist/database.js +503 -0
- package/dist/database.js.map +1 -0
- package/dist/index.js +121 -121
- package/dist/orchestrator.js +67 -67
- package/dist/ralph-manager.js +11 -11
- package/dist/ralph-manager.js.map +1 -1
- package/dist/tools/agents.js +84 -84
- package/dist/tools/utility.js +64 -64
- package/dist/types.d.ts +2 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +56 -54
package/dist/agent-spawner.js
CHANGED
|
@@ -331,91 +331,91 @@ function stripAnsiEscapes(str) {
|
|
|
331
331
|
function createWrapperScript(agent, cmd, args, promptFile, outputFile, promptDelivery, promptFlag) {
|
|
332
332
|
const argsJson = JSON.stringify(args);
|
|
333
333
|
const promptFlagJson = promptFlag ? JSON.stringify(promptFlag) : "null";
|
|
334
|
-
return `
|
|
335
|
-
import { spawn } from "child_process";
|
|
336
|
-
import * as fs from "fs";
|
|
337
|
-
|
|
338
|
-
const agent = ${JSON.stringify(agent)};
|
|
339
|
-
const cmd = ${JSON.stringify(cmd)};
|
|
340
|
-
const args = ${argsJson};
|
|
341
|
-
const promptFile = ${JSON.stringify(promptFile)};
|
|
342
|
-
const outputFile = ${JSON.stringify(outputFile)};
|
|
343
|
-
const promptDelivery = ${JSON.stringify(promptDelivery)};
|
|
344
|
-
const promptFlag = ${promptFlagJson};
|
|
345
|
-
|
|
346
|
-
// Read the prompt
|
|
347
|
-
const prompt = fs.readFileSync(promptFile, "utf-8");
|
|
348
|
-
|
|
349
|
-
// Build final args
|
|
350
|
-
const finalArgs = [...args];
|
|
351
|
-
if (promptDelivery === "flag" && promptFlag) {
|
|
352
|
-
finalArgs.push(promptFlag, prompt);
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
// Write header to output file
|
|
356
|
-
fs.writeFileSync(outputFile, \`Agent: \${agent}\\nStarted: \${new Date().toISOString()}\\n---\\n\`);
|
|
357
|
-
|
|
358
|
-
// Spawn the agent (use shell on Windows to resolve .cmd/.bat shims)
|
|
359
|
-
const proc = spawn(cmd, finalArgs, {
|
|
360
|
-
cwd: process.cwd(),
|
|
361
|
-
env: process.env,
|
|
362
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
363
|
-
shell: process.platform === "win32",
|
|
364
|
-
windowsHide: true,
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
let output = "";
|
|
368
|
-
|
|
369
|
-
proc.stdout.on("data", (data) => {
|
|
370
|
-
const text = data.toString();
|
|
371
|
-
output += text;
|
|
372
|
-
fs.appendFileSync(outputFile, text);
|
|
373
|
-
});
|
|
374
|
-
|
|
375
|
-
proc.stderr.on("data", (data) => {
|
|
376
|
-
const text = data.toString();
|
|
377
|
-
output += text;
|
|
378
|
-
fs.appendFileSync(outputFile, text);
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
// Send prompt via stdin if required, with backpressure handling
|
|
382
|
-
if (promptDelivery === "stdin") {
|
|
383
|
-
const CHUNK_SIZE = 16 * 1024;
|
|
384
|
-
let offset = 0;
|
|
385
|
-
function writeNext() {
|
|
386
|
-
let ok = true;
|
|
387
|
-
while (offset < prompt.length && ok) {
|
|
388
|
-
const chunk = prompt.slice(offset, offset + CHUNK_SIZE);
|
|
389
|
-
offset += chunk.length;
|
|
390
|
-
if (offset >= prompt.length) {
|
|
391
|
-
proc.stdin.end(chunk);
|
|
392
|
-
return;
|
|
393
|
-
}
|
|
394
|
-
ok = proc.stdin.write(chunk);
|
|
395
|
-
}
|
|
396
|
-
if (offset < prompt.length) {
|
|
397
|
-
proc.stdin.once("drain", writeNext);
|
|
398
|
-
}
|
|
399
|
-
}
|
|
400
|
-
writeNext();
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
proc.on("close", (code) => {
|
|
404
|
-
fs.appendFileSync(outputFile, \`\\n---\\nFinished: \${new Date().toISOString()}\\nExit Code: \${code}\\n\`);
|
|
405
|
-
// Clean up prompt file
|
|
406
|
-
try {
|
|
407
|
-
fs.unlinkSync(promptFile);
|
|
408
|
-
} catch {}
|
|
409
|
-
process.exit(code ?? 0);
|
|
410
|
-
});
|
|
411
|
-
|
|
412
|
-
proc.on("error", (err) => {
|
|
413
|
-
fs.appendFileSync(outputFile, \`\\n---\\nError: \${err.message}\\nFinished: \${new Date().toISOString()}\\nExit Code: 1\\n\`);
|
|
414
|
-
try {
|
|
415
|
-
fs.unlinkSync(promptFile);
|
|
416
|
-
} catch {}
|
|
417
|
-
process.exit(1);
|
|
418
|
-
});
|
|
334
|
+
return `
|
|
335
|
+
import { spawn } from "child_process";
|
|
336
|
+
import * as fs from "fs";
|
|
337
|
+
|
|
338
|
+
const agent = ${JSON.stringify(agent)};
|
|
339
|
+
const cmd = ${JSON.stringify(cmd)};
|
|
340
|
+
const args = ${argsJson};
|
|
341
|
+
const promptFile = ${JSON.stringify(promptFile)};
|
|
342
|
+
const outputFile = ${JSON.stringify(outputFile)};
|
|
343
|
+
const promptDelivery = ${JSON.stringify(promptDelivery)};
|
|
344
|
+
const promptFlag = ${promptFlagJson};
|
|
345
|
+
|
|
346
|
+
// Read the prompt
|
|
347
|
+
const prompt = fs.readFileSync(promptFile, "utf-8");
|
|
348
|
+
|
|
349
|
+
// Build final args
|
|
350
|
+
const finalArgs = [...args];
|
|
351
|
+
if (promptDelivery === "flag" && promptFlag) {
|
|
352
|
+
finalArgs.push(promptFlag, prompt);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
// Write header to output file
|
|
356
|
+
fs.writeFileSync(outputFile, \`Agent: \${agent}\\nStarted: \${new Date().toISOString()}\\n---\\n\`);
|
|
357
|
+
|
|
358
|
+
// Spawn the agent (use shell on Windows to resolve .cmd/.bat shims)
|
|
359
|
+
const proc = spawn(cmd, finalArgs, {
|
|
360
|
+
cwd: process.cwd(),
|
|
361
|
+
env: process.env,
|
|
362
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
363
|
+
shell: process.platform === "win32",
|
|
364
|
+
windowsHide: true,
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
let output = "";
|
|
368
|
+
|
|
369
|
+
proc.stdout.on("data", (data) => {
|
|
370
|
+
const text = data.toString();
|
|
371
|
+
output += text;
|
|
372
|
+
fs.appendFileSync(outputFile, text);
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
proc.stderr.on("data", (data) => {
|
|
376
|
+
const text = data.toString();
|
|
377
|
+
output += text;
|
|
378
|
+
fs.appendFileSync(outputFile, text);
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
// Send prompt via stdin if required, with backpressure handling
|
|
382
|
+
if (promptDelivery === "stdin") {
|
|
383
|
+
const CHUNK_SIZE = 16 * 1024;
|
|
384
|
+
let offset = 0;
|
|
385
|
+
function writeNext() {
|
|
386
|
+
let ok = true;
|
|
387
|
+
while (offset < prompt.length && ok) {
|
|
388
|
+
const chunk = prompt.slice(offset, offset + CHUNK_SIZE);
|
|
389
|
+
offset += chunk.length;
|
|
390
|
+
if (offset >= prompt.length) {
|
|
391
|
+
proc.stdin.end(chunk);
|
|
392
|
+
return;
|
|
393
|
+
}
|
|
394
|
+
ok = proc.stdin.write(chunk);
|
|
395
|
+
}
|
|
396
|
+
if (offset < prompt.length) {
|
|
397
|
+
proc.stdin.once("drain", writeNext);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
writeNext();
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
proc.on("close", (code) => {
|
|
404
|
+
fs.appendFileSync(outputFile, \`\\n---\\nFinished: \${new Date().toISOString()}\\nExit Code: \${code}\\n\`);
|
|
405
|
+
// Clean up prompt file
|
|
406
|
+
try {
|
|
407
|
+
fs.unlinkSync(promptFile);
|
|
408
|
+
} catch {}
|
|
409
|
+
process.exit(code ?? 0);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
proc.on("error", (err) => {
|
|
413
|
+
fs.appendFileSync(outputFile, \`\\n---\\nError: \${err.message}\\nFinished: \${new Date().toISOString()}\\nExit Code: 1\\n\`);
|
|
414
|
+
try {
|
|
415
|
+
fs.unlinkSync(promptFile);
|
|
416
|
+
} catch {}
|
|
417
|
+
process.exit(1);
|
|
418
|
+
});
|
|
419
419
|
`;
|
|
420
420
|
}
|
|
421
421
|
/**
|
package/dist/chat-manager.js
CHANGED
|
@@ -19,10 +19,10 @@ export class ChatManager {
|
|
|
19
19
|
fs.mkdirSync(this.chatDir, { recursive: true });
|
|
20
20
|
}
|
|
21
21
|
if (!fs.existsSync(this.chatFile)) {
|
|
22
|
-
const header = `# Robot Chat - Multi-Agent Communication
|
|
23
|
-
# Format: [AgentName @ HH:MM] MESSAGE_TYPE
|
|
24
|
-
# ========================================
|
|
25
|
-
|
|
22
|
+
const header = `# Robot Chat - Multi-Agent Communication
|
|
23
|
+
# Format: [AgentName @ HH:MM] MESSAGE_TYPE
|
|
24
|
+
# ========================================
|
|
25
|
+
|
|
26
26
|
`;
|
|
27
27
|
fs.writeFileSync(this.chatFile, header, "utf-8");
|
|
28
28
|
}
|
|
@@ -314,10 +314,10 @@ export class ChatManager {
|
|
|
314
314
|
}
|
|
315
315
|
fs.appendFileSync(archiveFile, archiveContent, "utf-8");
|
|
316
316
|
// Rewrite main chat file with only recent messages
|
|
317
|
-
const mainHeader = `# Robot Chat - Multi-Agent Communication
|
|
318
|
-
# Format: [AgentName @ HH:MM] MESSAGE_TYPE
|
|
319
|
-
# ========================================
|
|
320
|
-
|
|
317
|
+
const mainHeader = `# Robot Chat - Multi-Agent Communication
|
|
318
|
+
# Format: [AgentName @ HH:MM] MESSAGE_TYPE
|
|
319
|
+
# ========================================
|
|
320
|
+
|
|
321
321
|
`;
|
|
322
322
|
let mainContent = mainHeader;
|
|
323
323
|
for (const msg of toKeep) {
|
package/dist/cli.js
CHANGED
|
@@ -277,38 +277,38 @@ async function cmdFailover(chat, flags) {
|
|
|
277
277
|
output({ status: "posted", agent, type: "FAILOVER_NEEDED", task });
|
|
278
278
|
}
|
|
279
279
|
function cmdHelp() {
|
|
280
|
-
console.log(`
|
|
281
|
-
NightShift CLI - Multi-agent coordination without MCP
|
|
282
|
-
|
|
283
|
-
Usage: nightshift <command> [options]
|
|
284
|
-
|
|
285
|
-
Commands:
|
|
286
|
-
status Show PRD progress, bugs, active agents
|
|
287
|
-
next Get the next unclaimed story
|
|
288
|
-
claim [storyId] --agent <name> Claim a story (or next available)
|
|
289
|
-
complete <storyId> --agent <name> --summary "..." [--files "a,b"] [--learnings "..."]
|
|
290
|
-
Mark story complete, create savepoint
|
|
291
|
-
chat --read [--limit N] Read recent chat messages
|
|
292
|
-
chat --agent <name> --type <TYPE> --message "..."
|
|
293
|
-
Post a chat message
|
|
294
|
-
bug-claim [bugId] --agent <name> Claim a bug (or next available)
|
|
295
|
-
bug-fix <bugId> --agent <name> --summary "..." [--files "a,b"]
|
|
296
|
-
Mark bug fixed, create savepoint
|
|
297
|
-
failover --agent <name> --message "..." [--task "US-001"]
|
|
298
|
-
Post a failover request
|
|
299
|
-
help Show this help
|
|
300
|
-
|
|
301
|
-
Message Types: STATUS_UPDATE, INFO, QUESTION, ANSWER, ERROR, FAILOVER_NEEDED
|
|
302
|
-
|
|
303
|
-
Environment:
|
|
304
|
-
ROBOT_CHAT_PROJECT_PATH Project directory (default: cwd)
|
|
305
|
-
|
|
306
|
-
Examples:
|
|
307
|
-
nightshift status
|
|
308
|
-
nightshift claim US-001 --agent Codex
|
|
309
|
-
nightshift chat --agent Codex --type STATUS_UPDATE --message "Working on auth module"
|
|
310
|
-
nightshift complete US-001 --agent Codex --summary "Added JWT auth" --files "src/auth.ts,src/middleware.ts"
|
|
311
|
-
nightshift failover --agent Codex --task US-001 --message "Hit rate limit at 80%"
|
|
280
|
+
console.log(`
|
|
281
|
+
NightShift CLI - Multi-agent coordination without MCP
|
|
282
|
+
|
|
283
|
+
Usage: nightshift <command> [options]
|
|
284
|
+
|
|
285
|
+
Commands:
|
|
286
|
+
status Show PRD progress, bugs, active agents
|
|
287
|
+
next Get the next unclaimed story
|
|
288
|
+
claim [storyId] --agent <name> Claim a story (or next available)
|
|
289
|
+
complete <storyId> --agent <name> --summary "..." [--files "a,b"] [--learnings "..."]
|
|
290
|
+
Mark story complete, create savepoint
|
|
291
|
+
chat --read [--limit N] Read recent chat messages
|
|
292
|
+
chat --agent <name> --type <TYPE> --message "..."
|
|
293
|
+
Post a chat message
|
|
294
|
+
bug-claim [bugId] --agent <name> Claim a bug (or next available)
|
|
295
|
+
bug-fix <bugId> --agent <name> --summary "..." [--files "a,b"]
|
|
296
|
+
Mark bug fixed, create savepoint
|
|
297
|
+
failover --agent <name> --message "..." [--task "US-001"]
|
|
298
|
+
Post a failover request
|
|
299
|
+
help Show this help
|
|
300
|
+
|
|
301
|
+
Message Types: STATUS_UPDATE, INFO, QUESTION, ANSWER, ERROR, FAILOVER_NEEDED
|
|
302
|
+
|
|
303
|
+
Environment:
|
|
304
|
+
ROBOT_CHAT_PROJECT_PATH Project directory (default: cwd)
|
|
305
|
+
|
|
306
|
+
Examples:
|
|
307
|
+
nightshift status
|
|
308
|
+
nightshift claim US-001 --agent Codex
|
|
309
|
+
nightshift chat --agent Codex --type STATUS_UPDATE --message "Working on auth module"
|
|
310
|
+
nightshift complete US-001 --agent Codex --summary "Added JWT auth" --files "src/auth.ts,src/middleware.ts"
|
|
311
|
+
nightshift failover --agent Codex --task US-001 --message "Hit rate limit at 80%"
|
|
312
312
|
`);
|
|
313
313
|
}
|
|
314
314
|
// ============================================
|
package/dist/daemon-manager.js
CHANGED
|
@@ -117,75 +117,75 @@ export async function startDaemon(options) {
|
|
|
117
117
|
const wrapperFile = path.join(robotChatDir, `daemon-starter-${timestamp}.mjs`);
|
|
118
118
|
// Find the daemon entry point
|
|
119
119
|
// It could be installed globally or locally
|
|
120
|
-
const daemonScript = `
|
|
121
|
-
import { spawn } from "child_process";
|
|
122
|
-
import * as fs from "fs";
|
|
123
|
-
import * as path from "path";
|
|
124
|
-
|
|
125
|
-
const projectPath = ${JSON.stringify(projectPath)};
|
|
126
|
-
const logFile = ${JSON.stringify(logFile)};
|
|
127
|
-
const args = ${JSON.stringify(args)};
|
|
128
|
-
|
|
129
|
-
// Try to find the daemon module
|
|
130
|
-
// First check if nightshift-mcp is installed globally or locally
|
|
131
|
-
const possiblePaths = [
|
|
132
|
-
// Local node_modules
|
|
133
|
-
path.join(projectPath, "node_modules", "nightshift-mcp", "dist", "daemon.js"),
|
|
134
|
-
// If we're running from within the nightshift-mcp package itself
|
|
135
|
-
path.join(process.cwd(), "dist", "daemon.js"),
|
|
136
|
-
// Global npm installation (will use npx)
|
|
137
|
-
null,
|
|
138
|
-
];
|
|
139
|
-
|
|
140
|
-
let daemonPath = null;
|
|
141
|
-
for (const p of possiblePaths) {
|
|
142
|
-
if (p && fs.existsSync(p)) {
|
|
143
|
-
daemonPath = p;
|
|
144
|
-
break;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
// Write startup info to log
|
|
149
|
-
fs.writeFileSync(logFile, \`Daemon starting at \${new Date().toISOString()}\\n\`);
|
|
150
|
-
fs.appendFileSync(logFile, \`Project: \${projectPath}\\n\`);
|
|
151
|
-
fs.appendFileSync(logFile, \`Args: \${args.join(" ")}\\n---\\n\`);
|
|
152
|
-
|
|
153
|
-
const isWin = process.platform === "win32";
|
|
154
|
-
let proc;
|
|
155
|
-
if (daemonPath) {
|
|
156
|
-
fs.appendFileSync(logFile, \`Using daemon at: \${daemonPath}\\n\`);
|
|
157
|
-
// node is a real executable, NOT a .cmd shim — don't use shell (breaks paths with spaces)
|
|
158
|
-
proc = spawn("node", [daemonPath, ...args], {
|
|
159
|
-
cwd: projectPath,
|
|
160
|
-
env: {
|
|
161
|
-
...process.env,
|
|
162
|
-
ROBOT_CHAT_PROJECT_PATH: projectPath,
|
|
163
|
-
},
|
|
164
|
-
detached: true,
|
|
165
|
-
stdio: ["ignore", fs.openSync(logFile, "a"), fs.openSync(logFile, "a")],
|
|
166
|
-
windowsHide: true,
|
|
167
|
-
});
|
|
168
|
-
} else {
|
|
169
|
-
// Try npx as fallback — npx IS a .cmd shim on Windows, needs shell: true
|
|
170
|
-
fs.appendFileSync(logFile, "Using npx nightshift-daemon\\n");
|
|
171
|
-
proc = spawn("npx", ["nightshift-daemon", ...args], {
|
|
172
|
-
cwd: projectPath,
|
|
173
|
-
env: {
|
|
174
|
-
...process.env,
|
|
175
|
-
ROBOT_CHAT_PROJECT_PATH: projectPath,
|
|
176
|
-
},
|
|
177
|
-
detached: true,
|
|
178
|
-
stdio: ["ignore", fs.openSync(logFile, "a"), fs.openSync(logFile, "a")],
|
|
179
|
-
shell: isWin,
|
|
180
|
-
windowsHide: true,
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
proc.unref();
|
|
185
|
-
|
|
186
|
-
// Write PID for reference
|
|
187
|
-
fs.appendFileSync(logFile, \`Daemon PID: \${proc.pid}\\n\`);
|
|
188
|
-
console.log(JSON.stringify({ success: true, pid: proc.pid }));
|
|
120
|
+
const daemonScript = `
|
|
121
|
+
import { spawn } from "child_process";
|
|
122
|
+
import * as fs from "fs";
|
|
123
|
+
import * as path from "path";
|
|
124
|
+
|
|
125
|
+
const projectPath = ${JSON.stringify(projectPath)};
|
|
126
|
+
const logFile = ${JSON.stringify(logFile)};
|
|
127
|
+
const args = ${JSON.stringify(args)};
|
|
128
|
+
|
|
129
|
+
// Try to find the daemon module
|
|
130
|
+
// First check if nightshift-mcp is installed globally or locally
|
|
131
|
+
const possiblePaths = [
|
|
132
|
+
// Local node_modules
|
|
133
|
+
path.join(projectPath, "node_modules", "nightshift-mcp", "dist", "daemon.js"),
|
|
134
|
+
// If we're running from within the nightshift-mcp package itself
|
|
135
|
+
path.join(process.cwd(), "dist", "daemon.js"),
|
|
136
|
+
// Global npm installation (will use npx)
|
|
137
|
+
null,
|
|
138
|
+
];
|
|
139
|
+
|
|
140
|
+
let daemonPath = null;
|
|
141
|
+
for (const p of possiblePaths) {
|
|
142
|
+
if (p && fs.existsSync(p)) {
|
|
143
|
+
daemonPath = p;
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Write startup info to log
|
|
149
|
+
fs.writeFileSync(logFile, \`Daemon starting at \${new Date().toISOString()}\\n\`);
|
|
150
|
+
fs.appendFileSync(logFile, \`Project: \${projectPath}\\n\`);
|
|
151
|
+
fs.appendFileSync(logFile, \`Args: \${args.join(" ")}\\n---\\n\`);
|
|
152
|
+
|
|
153
|
+
const isWin = process.platform === "win32";
|
|
154
|
+
let proc;
|
|
155
|
+
if (daemonPath) {
|
|
156
|
+
fs.appendFileSync(logFile, \`Using daemon at: \${daemonPath}\\n\`);
|
|
157
|
+
// node is a real executable, NOT a .cmd shim — don't use shell (breaks paths with spaces)
|
|
158
|
+
proc = spawn("node", [daemonPath, ...args], {
|
|
159
|
+
cwd: projectPath,
|
|
160
|
+
env: {
|
|
161
|
+
...process.env,
|
|
162
|
+
ROBOT_CHAT_PROJECT_PATH: projectPath,
|
|
163
|
+
},
|
|
164
|
+
detached: true,
|
|
165
|
+
stdio: ["ignore", fs.openSync(logFile, "a"), fs.openSync(logFile, "a")],
|
|
166
|
+
windowsHide: true,
|
|
167
|
+
});
|
|
168
|
+
} else {
|
|
169
|
+
// Try npx as fallback — npx IS a .cmd shim on Windows, needs shell: true
|
|
170
|
+
fs.appendFileSync(logFile, "Using npx nightshift-daemon\\n");
|
|
171
|
+
proc = spawn("npx", ["nightshift-daemon", ...args], {
|
|
172
|
+
cwd: projectPath,
|
|
173
|
+
env: {
|
|
174
|
+
...process.env,
|
|
175
|
+
ROBOT_CHAT_PROJECT_PATH: projectPath,
|
|
176
|
+
},
|
|
177
|
+
detached: true,
|
|
178
|
+
stdio: ["ignore", fs.openSync(logFile, "a"), fs.openSync(logFile, "a")],
|
|
179
|
+
shell: isWin,
|
|
180
|
+
windowsHide: true,
|
|
181
|
+
});
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
proc.unref();
|
|
185
|
+
|
|
186
|
+
// Write PID for reference
|
|
187
|
+
fs.appendFileSync(logFile, \`Daemon PID: \${proc.pid}\\n\`);
|
|
188
|
+
console.log(JSON.stringify({ success: true, pid: proc.pid }));
|
|
189
189
|
`;
|
|
190
190
|
try {
|
|
191
191
|
// Write the wrapper script
|
package/dist/daemon.d.ts
CHANGED
|
@@ -16,15 +16,20 @@ interface DaemonConfig {
|
|
|
16
16
|
agents: AgentType[];
|
|
17
17
|
verbose: boolean;
|
|
18
18
|
dryRun: boolean;
|
|
19
|
+
circuitBreakerThreshold: number;
|
|
20
|
+
circuitBreakerCooldownMs: number;
|
|
19
21
|
}
|
|
22
|
+
type CircuitState = "CLOSED" | "OPEN" | "HALF_OPEN";
|
|
20
23
|
export declare class NightShiftDaemon {
|
|
21
24
|
private config;
|
|
22
25
|
private ralph;
|
|
23
26
|
private chat;
|
|
24
27
|
private workflow;
|
|
28
|
+
private db;
|
|
25
29
|
private running;
|
|
26
30
|
private activeAgents;
|
|
27
31
|
private storyStates;
|
|
32
|
+
private agentCircuits;
|
|
28
33
|
private availableAgents;
|
|
29
34
|
private agentIndex;
|
|
30
35
|
private prdWatcher;
|
|
@@ -47,6 +52,22 @@ export declare class NightShiftDaemon {
|
|
|
47
52
|
private onPrdChanged;
|
|
48
53
|
private onChatChanged;
|
|
49
54
|
private handleFailover;
|
|
55
|
+
private initializeCircuits;
|
|
56
|
+
private recordAgentFailure;
|
|
57
|
+
private recordAgentSuccess;
|
|
58
|
+
/**
|
|
59
|
+
* Try to reserve an agent for work. Returns true if the agent is available.
|
|
60
|
+
* For HALF_OPEN state, only one probe is allowed at a time.
|
|
61
|
+
*/
|
|
62
|
+
private tryReserveAgent;
|
|
63
|
+
private releaseProbe;
|
|
64
|
+
private getHealthyAgents;
|
|
65
|
+
getCircuitStatus(): Record<string, {
|
|
66
|
+
state: CircuitState;
|
|
67
|
+
failures: number;
|
|
68
|
+
successes: number;
|
|
69
|
+
consecutiveFailures: number;
|
|
70
|
+
}>;
|
|
50
71
|
private reconcile;
|
|
51
72
|
private getNextAgent;
|
|
52
73
|
private spawnAgentForStory;
|
package/dist/daemon.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAQH,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"daemon.d.ts","sourceRoot":"","sources":["../src/daemon.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAQH,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,oBAAoB,CAAC;AAQ5B,UAAU,YAAY;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,gBAAgB,EAAE,MAAM,CAAC;IACzB,YAAY,EAAE,MAAM,CAAC;IACrB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,SAAS,EAAE,CAAC;IACpB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,uBAAuB,EAAE,MAAM,CAAC;IAChC,wBAAwB,EAAE,MAAM,CAAC;CAClC;AAmBD,KAAK,YAAY,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,CAAC;AAiBpD,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAe;IAC7B,OAAO,CAAC,KAAK,CAAe;IAC5B,OAAO,CAAC,IAAI,CAAc;IAC1B,OAAO,CAAC,QAAQ,CAAkB;IAClC,OAAO,CAAC,EAAE,CAAe;IAGzB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,YAAY,CAAwC;IAC5D,OAAO,CAAC,WAAW,CAAsC;IACzD,OAAO,CAAC,aAAa,CAAgD;IACrE,OAAO,CAAC,eAAe,CAAmB;IAC1C,OAAO,CAAC,UAAU,CAAK;IAGvB,OAAO,CAAC,UAAU,CAA6B;IAC/C,OAAO,CAAC,WAAW,CAA6B;IAChD,OAAO,CAAC,eAAe,CAAQ;IAG/B,OAAO,CAAC,gBAAgB,CAA+B;IACvD,OAAO,CAAC,cAAc,CAA0C;IAGhE,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,MAAM,CAAuB;gBAEzB,MAAM,EAAE,OAAO,CAAC,YAAY,CAAC,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE;IA0BnE,OAAO,CAAC,GAAG;IAwBX,OAAO,CAAC,WAAW;IAmCnB,OAAO,CAAC,WAAW;IAkBnB,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,YAAY;IAWpB,OAAO,CAAC,eAAe;IAMvB,OAAO,CAAC,QAAQ;YAkBF,YAAY;YAKZ,aAAa;YAwBb,cAAc;IA2B5B,OAAO,CAAC,kBAAkB;IAuB1B,OAAO,CAAC,kBAAkB;IAsC1B,OAAO,CAAC,kBAAkB;IAyB1B;;;OAGG;IACH,OAAO,CAAC,eAAe;IA0CvB,OAAO,CAAC,YAAY;IAOpB,OAAO,CAAC,gBAAgB;IAexB,gBAAgB,IAAI,MAAM,CAAC,MAAM,EAAE;QAAE,KAAK,EAAE,YAAY,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,mBAAmB,EAAE,MAAM,CAAA;KAAE,CAAC;YAiB/G,SAAS;IA6CvB,OAAO,CAAC,YAAY;YAQN,kBAAkB;IAgFhC,OAAO,CAAC,gBAAgB;IAgCxB,OAAO,CAAC,YAAY;YAaN,WAAW;IA2CzB,OAAO,CAAC,cAAc;IAmBtB,OAAO,CAAC,aAAa;IAQrB,OAAO,CAAC,gBAAgB;IAUxB,OAAO,CAAC,eAAe;YAOT,WAAW;IAgDnB,KAAK;IA0CL,QAAQ;CAuBf"}
|