nightshift-mcp 2.2.0 → 2.3.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 +65 -3
- package/dist/config.d.ts +100 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +208 -0
- package/dist/config.js.map +1 -0
- package/dist/daemon-manager.d.ts +24 -0
- package/dist/daemon-manager.d.ts.map +1 -1
- package/dist/daemon-manager.js +142 -0
- package/dist/daemon-manager.js.map +1 -1
- package/dist/daemon.d.ts +12 -0
- package/dist/daemon.d.ts.map +1 -1
- package/dist/daemon.js +179 -38
- package/dist/daemon.js.map +1 -1
- package/dist/routines.d.ts +64 -0
- package/dist/routines.d.ts.map +1 -0
- package/dist/routines.js +247 -0
- package/dist/routines.js.map +1 -0
- package/dist/tools/agents.d.ts +8 -0
- package/dist/tools/agents.d.ts.map +1 -1
- package/dist/tools/agents.js +295 -1
- package/dist/tools/agents.js.map +1 -1
- package/dist/vision.d.ts +1 -1
- package/dist/vision.d.ts.map +1 -1
- package/dist/vision.js +11 -21
- package/dist/vision.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NightShift Routines Engine
|
|
3
|
+
*
|
|
4
|
+
* Recurring maintenance tasks that run on schedule during "maintain" mode.
|
|
5
|
+
* Routines generate bugs/stories rather than being stories themselves —
|
|
6
|
+
* they're the autonomous equivalent of cron jobs for codebase health.
|
|
7
|
+
*
|
|
8
|
+
* Unlike sprint stories (finite, one-shot), routines are infinite and recurring:
|
|
9
|
+
* - Security audits
|
|
10
|
+
* - Dependency updates
|
|
11
|
+
* - Test coverage improvement
|
|
12
|
+
* - Performance monitoring
|
|
13
|
+
*/
|
|
14
|
+
import { type AgentType } from "./agent-spawner.js";
|
|
15
|
+
import { ChatManager } from "./chat-manager.js";
|
|
16
|
+
import type { RoutineConfig } from "./config.js";
|
|
17
|
+
export interface RoutineRun {
|
|
18
|
+
routine: string;
|
|
19
|
+
startedAt: string;
|
|
20
|
+
completedAt?: string;
|
|
21
|
+
success: boolean;
|
|
22
|
+
output?: string;
|
|
23
|
+
error?: string;
|
|
24
|
+
agent: AgentType;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check if a routine is due to run based on its schedule and last run time.
|
|
28
|
+
*/
|
|
29
|
+
export declare function isRoutineDue(routine: RoutineConfig, lastRun?: string): boolean;
|
|
30
|
+
/**
|
|
31
|
+
* Execute a single routine.
|
|
32
|
+
*/
|
|
33
|
+
export declare function executeRoutine(routine: RoutineConfig, projectPath: string, chat: ChatManager): Promise<RoutineRun>;
|
|
34
|
+
/**
|
|
35
|
+
* Check all routines and execute any that are due.
|
|
36
|
+
* Returns the number of routines that were executed.
|
|
37
|
+
*
|
|
38
|
+
* Called by the daemon during maintain mode reconciliation.
|
|
39
|
+
* Runs routines sequentially to avoid overwhelming the system.
|
|
40
|
+
*/
|
|
41
|
+
export declare function runDueRoutines(routines: RoutineConfig[], projectPath: string, chat: ChatManager, maxConcurrent?: number): Promise<{
|
|
42
|
+
executed: number;
|
|
43
|
+
succeeded: number;
|
|
44
|
+
failed: number;
|
|
45
|
+
}>;
|
|
46
|
+
/**
|
|
47
|
+
* Get the current state of all routines (for status display).
|
|
48
|
+
*/
|
|
49
|
+
export declare function getRoutineStatus(routines: RoutineConfig[], projectPath: string): Array<{
|
|
50
|
+
name: string;
|
|
51
|
+
type: string;
|
|
52
|
+
schedule: string;
|
|
53
|
+
agent: string;
|
|
54
|
+
enabled: boolean;
|
|
55
|
+
lastRun?: string;
|
|
56
|
+
nextDue: boolean;
|
|
57
|
+
consecutiveFailures: number;
|
|
58
|
+
circuitOpen: boolean;
|
|
59
|
+
}>;
|
|
60
|
+
/**
|
|
61
|
+
* Reset a routine's failure count (re-enable after circuit break).
|
|
62
|
+
*/
|
|
63
|
+
export declare function resetRoutine(projectPath: string, routineName: string): boolean;
|
|
64
|
+
//# sourceMappingURL=routines.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routines.d.ts","sourceRoot":"","sources":["../src/routines.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAIH,OAAO,EAAc,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAChE,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,aAAa,EAAmB,MAAM,aAAa,CAAC;AAMlE,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,SAAS,CAAC;CAClB;AA2BD;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,aAAa,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAQ9E;AAyDD;;GAEG;AACH,wBAAsB,cAAc,CAClC,OAAO,EAAE,aAAa,EACtB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,WAAW,GAChB,OAAO,CAAC,UAAU,CAAC,CA2ErB;AAMD;;;;;;GAMG;AACH,wBAAsB,cAAc,CAClC,QAAQ,EAAE,aAAa,EAAE,EACzB,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,WAAW,EACjB,aAAa,GAAE,MAAU,GACxB,OAAO,CAAC;IAAE,QAAQ,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAsDlE;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAC9B,QAAQ,EAAE,aAAa,EAAE,EACzB,WAAW,EAAE,MAAM,GAClB,KAAK,CAAC;IACP,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,MAAM,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC,CAiBD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,GAAG,OAAO,CAS9E"}
|
package/dist/routines.js
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NightShift Routines Engine
|
|
3
|
+
*
|
|
4
|
+
* Recurring maintenance tasks that run on schedule during "maintain" mode.
|
|
5
|
+
* Routines generate bugs/stories rather than being stories themselves —
|
|
6
|
+
* they're the autonomous equivalent of cron jobs for codebase health.
|
|
7
|
+
*
|
|
8
|
+
* Unlike sprint stories (finite, one-shot), routines are infinite and recurring:
|
|
9
|
+
* - Security audits
|
|
10
|
+
* - Dependency updates
|
|
11
|
+
* - Test coverage improvement
|
|
12
|
+
* - Performance monitoring
|
|
13
|
+
*/
|
|
14
|
+
import * as fs from "fs";
|
|
15
|
+
import * as path from "path";
|
|
16
|
+
import { spawnAgent } from "./agent-spawner.js";
|
|
17
|
+
// ============================================
|
|
18
|
+
// Schedule Helpers
|
|
19
|
+
// ============================================
|
|
20
|
+
/**
|
|
21
|
+
* Get the interval in milliseconds for a schedule cadence.
|
|
22
|
+
*/
|
|
23
|
+
function scheduleToMs(schedule) {
|
|
24
|
+
switch (schedule) {
|
|
25
|
+
case "hourly": return 60 * 60 * 1000;
|
|
26
|
+
case "daily": return 24 * 60 * 60 * 1000;
|
|
27
|
+
case "weekly": return 7 * 24 * 60 * 60 * 1000;
|
|
28
|
+
case "monthly": return 30 * 24 * 60 * 60 * 1000;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Check if a routine is due to run based on its schedule and last run time.
|
|
33
|
+
*/
|
|
34
|
+
export function isRoutineDue(routine, lastRun) {
|
|
35
|
+
if (!lastRun)
|
|
36
|
+
return true; // Never run before
|
|
37
|
+
const lastRunTime = new Date(lastRun).getTime();
|
|
38
|
+
const interval = scheduleToMs(routine.schedule);
|
|
39
|
+
const now = Date.now();
|
|
40
|
+
return (now - lastRunTime) >= interval;
|
|
41
|
+
}
|
|
42
|
+
// ============================================
|
|
43
|
+
// Routine State Persistence
|
|
44
|
+
// ============================================
|
|
45
|
+
const STATE_FILENAME = "routine-state.json";
|
|
46
|
+
/**
|
|
47
|
+
* Load routine execution state from disk.
|
|
48
|
+
*/
|
|
49
|
+
function loadRoutineState(projectPath) {
|
|
50
|
+
const stateFile = path.join(projectPath, ".robot-chat", STATE_FILENAME);
|
|
51
|
+
if (!fs.existsSync(stateFile))
|
|
52
|
+
return {};
|
|
53
|
+
try {
|
|
54
|
+
return JSON.parse(fs.readFileSync(stateFile, "utf-8"));
|
|
55
|
+
}
|
|
56
|
+
catch {
|
|
57
|
+
return {};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Save routine execution state to disk.
|
|
62
|
+
*/
|
|
63
|
+
function saveRoutineState(projectPath, state) {
|
|
64
|
+
const dir = path.join(projectPath, ".robot-chat");
|
|
65
|
+
if (!fs.existsSync(dir)) {
|
|
66
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
67
|
+
}
|
|
68
|
+
fs.writeFileSync(path.join(dir, STATE_FILENAME), JSON.stringify(state, null, 2), "utf-8");
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Append a routine run to the run log.
|
|
72
|
+
*/
|
|
73
|
+
function logRoutineRun(projectPath, run) {
|
|
74
|
+
const logFile = path.join(projectPath, ".robot-chat", "routine-runs.jsonl");
|
|
75
|
+
const dir = path.dirname(logFile);
|
|
76
|
+
if (!fs.existsSync(dir)) {
|
|
77
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
78
|
+
}
|
|
79
|
+
fs.appendFileSync(logFile, JSON.stringify(run) + "\n", "utf-8");
|
|
80
|
+
}
|
|
81
|
+
// ============================================
|
|
82
|
+
// Routine Execution
|
|
83
|
+
// ============================================
|
|
84
|
+
/**
|
|
85
|
+
* Execute a single routine.
|
|
86
|
+
*/
|
|
87
|
+
export async function executeRoutine(routine, projectPath, chat) {
|
|
88
|
+
const startedAt = new Date().toISOString();
|
|
89
|
+
chat.writeMessage({
|
|
90
|
+
agent: "NightShift",
|
|
91
|
+
type: "INFO",
|
|
92
|
+
content: `Running routine "${routine.name}" (${routine.type}, ${routine.schedule}) with ${routine.agent}`,
|
|
93
|
+
});
|
|
94
|
+
// Build the routine prompt with context
|
|
95
|
+
const fullPrompt = `You are running a scheduled maintenance routine for this project.
|
|
96
|
+
|
|
97
|
+
## Routine: ${routine.name}
|
|
98
|
+
## Type: ${routine.type}
|
|
99
|
+
## Schedule: ${routine.schedule}
|
|
100
|
+
|
|
101
|
+
## Instructions
|
|
102
|
+
${routine.prompt}
|
|
103
|
+
|
|
104
|
+
## Important
|
|
105
|
+
- This is a recurring maintenance task, not a feature implementation
|
|
106
|
+
- If you find issues, file them as bugs using the nightshift CLI: nightshift bug-claim BUG-XXX
|
|
107
|
+
- If you identify needed features, file them as stories (they'll be picked up in the next sprint)
|
|
108
|
+
- Commit any direct fixes (e.g., dependency updates, test additions)
|
|
109
|
+
- Keep changes small and focused — this is maintenance, not refactoring
|
|
110
|
+
- Report a summary of what you found and what actions you took`;
|
|
111
|
+
try {
|
|
112
|
+
const result = await spawnAgent({
|
|
113
|
+
agent: routine.agent,
|
|
114
|
+
prompt: fullPrompt,
|
|
115
|
+
projectPath,
|
|
116
|
+
timeout: (routine.timeout ?? 600) * 1000,
|
|
117
|
+
role: `routine-${routine.type}`,
|
|
118
|
+
});
|
|
119
|
+
const run = {
|
|
120
|
+
routine: routine.name,
|
|
121
|
+
startedAt,
|
|
122
|
+
completedAt: new Date().toISOString(),
|
|
123
|
+
success: result.success,
|
|
124
|
+
output: result.output?.slice(0, 2000), // Cap output in log
|
|
125
|
+
agent: routine.agent,
|
|
126
|
+
};
|
|
127
|
+
if (!result.success) {
|
|
128
|
+
run.error = result.error;
|
|
129
|
+
chat.writeMessage({
|
|
130
|
+
agent: "NightShift",
|
|
131
|
+
type: "ERROR",
|
|
132
|
+
content: `Routine "${routine.name}" failed: ${result.error || "unknown error"}`,
|
|
133
|
+
});
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
chat.writeMessage({
|
|
137
|
+
agent: "NightShift",
|
|
138
|
+
type: "INFO",
|
|
139
|
+
content: `Routine "${routine.name}" completed successfully`,
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
logRoutineRun(projectPath, run);
|
|
143
|
+
return run;
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const run = {
|
|
147
|
+
routine: routine.name,
|
|
148
|
+
startedAt,
|
|
149
|
+
completedAt: new Date().toISOString(),
|
|
150
|
+
success: false,
|
|
151
|
+
error: err instanceof Error ? err.message : String(err),
|
|
152
|
+
agent: routine.agent,
|
|
153
|
+
};
|
|
154
|
+
logRoutineRun(projectPath, run);
|
|
155
|
+
return run;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
// ============================================
|
|
159
|
+
// Routine Scheduler (called by daemon)
|
|
160
|
+
// ============================================
|
|
161
|
+
/**
|
|
162
|
+
* Check all routines and execute any that are due.
|
|
163
|
+
* Returns the number of routines that were executed.
|
|
164
|
+
*
|
|
165
|
+
* Called by the daemon during maintain mode reconciliation.
|
|
166
|
+
* Runs routines sequentially to avoid overwhelming the system.
|
|
167
|
+
*/
|
|
168
|
+
export async function runDueRoutines(routines, projectPath, chat, maxConcurrent = 1) {
|
|
169
|
+
const state = loadRoutineState(projectPath);
|
|
170
|
+
const enabledRoutines = routines.filter(r => r.enabled !== false);
|
|
171
|
+
// Find routines that are due
|
|
172
|
+
const dueRoutines = enabledRoutines.filter(r => {
|
|
173
|
+
const routineState = state[r.name];
|
|
174
|
+
// Skip if already running
|
|
175
|
+
if (routineState?.running)
|
|
176
|
+
return false;
|
|
177
|
+
// Skip if too many consecutive failures (circuit breaker)
|
|
178
|
+
if (routineState?.consecutiveFailures && routineState.consecutiveFailures >= 3) {
|
|
179
|
+
return false;
|
|
180
|
+
}
|
|
181
|
+
return isRoutineDue(r, routineState?.lastRun);
|
|
182
|
+
});
|
|
183
|
+
if (dueRoutines.length === 0) {
|
|
184
|
+
return { executed: 0, succeeded: 0, failed: 0 };
|
|
185
|
+
}
|
|
186
|
+
let executed = 0;
|
|
187
|
+
let succeeded = 0;
|
|
188
|
+
let failed = 0;
|
|
189
|
+
// Run routines (sequentially for now, respecting maxConcurrent)
|
|
190
|
+
for (const routine of dueRoutines.slice(0, maxConcurrent)) {
|
|
191
|
+
// Mark as running
|
|
192
|
+
if (!state[routine.name]) {
|
|
193
|
+
state[routine.name] = { consecutiveFailures: 0, running: false };
|
|
194
|
+
}
|
|
195
|
+
state[routine.name].running = true;
|
|
196
|
+
saveRoutineState(projectPath, state);
|
|
197
|
+
const run = await executeRoutine(routine, projectPath, chat);
|
|
198
|
+
executed++;
|
|
199
|
+
// Update state
|
|
200
|
+
state[routine.name].running = false;
|
|
201
|
+
if (run.success) {
|
|
202
|
+
state[routine.name].lastRun = run.completedAt;
|
|
203
|
+
state[routine.name].consecutiveFailures = 0;
|
|
204
|
+
succeeded++;
|
|
205
|
+
}
|
|
206
|
+
else {
|
|
207
|
+
state[routine.name].consecutiveFailures =
|
|
208
|
+
(state[routine.name].consecutiveFailures || 0) + 1;
|
|
209
|
+
failed++;
|
|
210
|
+
}
|
|
211
|
+
saveRoutineState(projectPath, state);
|
|
212
|
+
}
|
|
213
|
+
return { executed, succeeded, failed };
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Get the current state of all routines (for status display).
|
|
217
|
+
*/
|
|
218
|
+
export function getRoutineStatus(routines, projectPath) {
|
|
219
|
+
const state = loadRoutineState(projectPath);
|
|
220
|
+
return routines.map(r => {
|
|
221
|
+
const s = state[r.name] || { consecutiveFailures: 0, running: false };
|
|
222
|
+
return {
|
|
223
|
+
name: r.name,
|
|
224
|
+
type: r.type,
|
|
225
|
+
schedule: r.schedule,
|
|
226
|
+
agent: r.agent,
|
|
227
|
+
enabled: r.enabled !== false,
|
|
228
|
+
lastRun: s.lastRun,
|
|
229
|
+
nextDue: isRoutineDue(r, s.lastRun),
|
|
230
|
+
consecutiveFailures: s.consecutiveFailures,
|
|
231
|
+
circuitOpen: s.consecutiveFailures >= 3,
|
|
232
|
+
};
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Reset a routine's failure count (re-enable after circuit break).
|
|
237
|
+
*/
|
|
238
|
+
export function resetRoutine(projectPath, routineName) {
|
|
239
|
+
const state = loadRoutineState(projectPath);
|
|
240
|
+
if (!state[routineName])
|
|
241
|
+
return false;
|
|
242
|
+
state[routineName].consecutiveFailures = 0;
|
|
243
|
+
state[routineName].running = false;
|
|
244
|
+
saveRoutineState(projectPath, state);
|
|
245
|
+
return true;
|
|
246
|
+
}
|
|
247
|
+
//# sourceMappingURL=routines.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"routines.js","sourceRoot":"","sources":["../src/routines.ts"],"names":[],"mappings":"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"}
|
package/dist/tools/agents.d.ts
CHANGED
|
@@ -11,5 +11,13 @@ export declare const stopDaemonTool: import("../tool-registry.js").ToolDefinitio
|
|
|
11
11
|
export declare const getRunStatsTool: import("../tool-registry.js").ToolDefinition;
|
|
12
12
|
export declare const getPipelineTool: import("../tool-registry.js").ToolDefinition;
|
|
13
13
|
export declare const setPipelineTool: import("../tool-registry.js").ToolDefinition;
|
|
14
|
+
export declare const setScheduleTool: import("../tool-registry.js").ToolDefinition;
|
|
15
|
+
export declare const getScheduleTool: import("../tool-registry.js").ToolDefinition;
|
|
16
|
+
export declare const removeScheduleTool: import("../tool-registry.js").ToolDefinition;
|
|
17
|
+
export declare const setModeTool: import("../tool-registry.js").ToolDefinition;
|
|
18
|
+
export declare const getModeTool: import("../tool-registry.js").ToolDefinition;
|
|
19
|
+
export declare const listRoutinesTool: import("../tool-registry.js").ToolDefinition;
|
|
20
|
+
export declare const addRoutineTool: import("../tool-registry.js").ToolDefinition;
|
|
21
|
+
export declare const resetRoutineTool: import("../tool-registry.js").ToolDefinition;
|
|
14
22
|
export declare const agentTools: import("../tool-registry.js").ToolDefinition[];
|
|
15
23
|
//# sourceMappingURL=agents.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/tools/agents.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"agents.d.ts","sourceRoot":"","sources":["../../src/tools/agents.ts"],"names":[],"mappings":"AAgFA,eAAO,MAAM,mBAAmB,8CAsC9B,CAAC;AAEH,eAAO,MAAM,cAAc,8CAiGzB,CAAC;AAEH,eAAO,MAAM,wBAAwB,8CAuDnC,CAAC;AAEH,eAAO,MAAM,aAAa,8CA6LxB,CAAC;AAEH,eAAO,MAAM,gBAAgB,8CAoK3B,CAAC;AAEH,eAAO,MAAM,WAAW,8CA0JtB,CAAC;AAEH,eAAO,MAAM,kBAAkB,8CAyC7B,CAAC;AAEH,eAAO,MAAM,qBAAqB,8CAyChC,CAAC;AAEH,eAAO,MAAM,mBAAmB,8CAsB9B,CAAC;AAEH,eAAO,MAAM,cAAc,8CA4CzB,CAAC;AAEH,eAAO,MAAM,eAAe,8CAgC1B,CAAC;AAEH,eAAO,MAAM,eAAe,8CA8B1B,CAAC;AAEH,eAAO,MAAM,eAAe,8CA0D1B,CAAC;AAOH,eAAO,MAAM,eAAe,8CAiD1B,CAAC;AAEH,eAAO,MAAM,eAAe,8CAmB1B,CAAC;AAEH,eAAO,MAAM,kBAAkB,8CAmB7B,CAAC;AAMH,eAAO,MAAM,WAAW,8CAwCtB,CAAC;AAEH,eAAO,MAAM,WAAW,8CAgCtB,CAAC;AAMH,eAAO,MAAM,gBAAgB,8CA0C3B,CAAC;AAEH,eAAO,MAAM,cAAc,8CAgEzB,CAAC;AAEH,eAAO,MAAM,gBAAgB,8CAqB3B,CAAC;AAEH,eAAO,MAAM,UAAU,gDAsBtB,CAAC"}
|
package/dist/tools/agents.js
CHANGED
|
@@ -5,7 +5,9 @@ import { getNightshiftCliCommand } from "../platform.js";
|
|
|
5
5
|
import { getRunStats, readRunLog } from "../run-logger.js";
|
|
6
6
|
import { savePipelineOverride, clearPipelineOverride, resolveExecutablePipeline, listPipelines, getTagRouting, } from "../pipeline.js";
|
|
7
7
|
import { ProjectOrchestrator } from "../orchestrator.js";
|
|
8
|
-
import { isDaemonRunning, ensureDaemonRunning, stopDaemon, installWatchdog, } from "../daemon-manager.js";
|
|
8
|
+
import { isDaemonRunning, ensureDaemonRunning, stopDaemon, installWatchdog, installSchedule, removeSchedule, getSchedule, } from "../daemon-manager.js";
|
|
9
|
+
import { loadConfig, saveConfig, getDefaultRoutines } from "../config.js";
|
|
10
|
+
import { getRoutineStatus, resetRoutine } from "../routines.js";
|
|
9
11
|
const AGENT_TYPES = ["claude", "codex", "gemini", "vibe", "goose", "ollama"];
|
|
10
12
|
/**
|
|
11
13
|
* Pre-flight check: verify an agent is installed and can run before attempting to spawn it.
|
|
@@ -963,6 +965,290 @@ Use reset=true to clear all runtime overrides and revert to defaults + config fi
|
|
|
963
965
|
},
|
|
964
966
|
});
|
|
965
967
|
// Export all agent tools as an array
|
|
968
|
+
// ============================================
|
|
969
|
+
// Schedule Tools
|
|
970
|
+
// ============================================
|
|
971
|
+
export const setScheduleTool = defineTool({
|
|
972
|
+
name: "set_schedule",
|
|
973
|
+
category: "agents",
|
|
974
|
+
description: "Set a daily start/stop schedule for the daemon",
|
|
975
|
+
fullDescription: `Schedule the daemon to start and stop at specific times each day.
|
|
976
|
+
|
|
977
|
+
This installs cron entries (Unix) or scheduled tasks (Windows) that automatically
|
|
978
|
+
start and stop the daemon within a time window. Perfect for overnight autonomous operation.
|
|
979
|
+
|
|
980
|
+
Example: Start at 1AM, stop at 5AM on weekdays:
|
|
981
|
+
set_schedule({ start: "01:00", stop: "05:00", days: ["mon","tue","wed","thu","fri"] })`,
|
|
982
|
+
inputSchema: z.object({
|
|
983
|
+
start: z.string().describe("Start time in HH:MM 24h format (e.g., '01:00')"),
|
|
984
|
+
stop: z.string().describe("Stop time in HH:MM 24h format (e.g., '05:00')"),
|
|
985
|
+
timezone: z.string().optional().describe("IANA timezone (e.g., 'America/Chicago'). Default: system timezone"),
|
|
986
|
+
days: z.array(z.enum(["mon", "tue", "wed", "thu", "fri", "sat", "sun"])).optional()
|
|
987
|
+
.describe("Days to run (default: every day)"),
|
|
988
|
+
}),
|
|
989
|
+
handler: async (params, ctx) => {
|
|
990
|
+
const schedule = {
|
|
991
|
+
start: params.start,
|
|
992
|
+
stop: params.stop,
|
|
993
|
+
timezone: params.timezone,
|
|
994
|
+
days: params.days,
|
|
995
|
+
};
|
|
996
|
+
const result = installSchedule(ctx.projectPath, schedule);
|
|
997
|
+
if (result.success) {
|
|
998
|
+
ctx.chatManager.writeMessage({
|
|
999
|
+
agent: "NightShift",
|
|
1000
|
+
type: "INFO",
|
|
1001
|
+
content: `Schedule installed: ${result.details}`,
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
return {
|
|
1005
|
+
content: [{
|
|
1006
|
+
type: "text",
|
|
1007
|
+
text: JSON.stringify({
|
|
1008
|
+
success: result.success,
|
|
1009
|
+
details: result.details,
|
|
1010
|
+
error: result.error,
|
|
1011
|
+
schedule,
|
|
1012
|
+
}, null, 2),
|
|
1013
|
+
}],
|
|
1014
|
+
isError: !result.success,
|
|
1015
|
+
};
|
|
1016
|
+
},
|
|
1017
|
+
});
|
|
1018
|
+
export const getScheduleTool = defineTool({
|
|
1019
|
+
name: "get_schedule",
|
|
1020
|
+
category: "agents",
|
|
1021
|
+
description: "Get the current daemon schedule",
|
|
1022
|
+
fullDescription: "View the current start/stop schedule for the daemon.",
|
|
1023
|
+
inputSchema: z.object({}),
|
|
1024
|
+
handler: async (_params, ctx) => {
|
|
1025
|
+
const schedule = getSchedule(ctx.projectPath);
|
|
1026
|
+
return {
|
|
1027
|
+
content: [{
|
|
1028
|
+
type: "text",
|
|
1029
|
+
text: JSON.stringify({
|
|
1030
|
+
hasSchedule: !!schedule,
|
|
1031
|
+
schedule: schedule ?? "No schedule configured. Use set_schedule to add one.",
|
|
1032
|
+
}, null, 2),
|
|
1033
|
+
}],
|
|
1034
|
+
};
|
|
1035
|
+
},
|
|
1036
|
+
});
|
|
1037
|
+
export const removeScheduleTool = defineTool({
|
|
1038
|
+
name: "remove_schedule",
|
|
1039
|
+
category: "agents",
|
|
1040
|
+
description: "Remove the daemon schedule",
|
|
1041
|
+
fullDescription: "Remove the start/stop schedule for the daemon. The daemon will no longer auto-start/stop on a timer.",
|
|
1042
|
+
inputSchema: z.object({}),
|
|
1043
|
+
handler: async (_params, ctx) => {
|
|
1044
|
+
const result = removeSchedule(ctx.projectPath);
|
|
1045
|
+
return {
|
|
1046
|
+
content: [{
|
|
1047
|
+
type: "text",
|
|
1048
|
+
text: JSON.stringify({
|
|
1049
|
+
success: result.success,
|
|
1050
|
+
message: result.success ? "Schedule removed" : result.error,
|
|
1051
|
+
}, null, 2),
|
|
1052
|
+
}],
|
|
1053
|
+
};
|
|
1054
|
+
},
|
|
1055
|
+
});
|
|
1056
|
+
// ============================================
|
|
1057
|
+
// Mode Tools
|
|
1058
|
+
// ============================================
|
|
1059
|
+
export const setModeTool = defineTool({
|
|
1060
|
+
name: "set_mode",
|
|
1061
|
+
category: "agents",
|
|
1062
|
+
description: "Set the daemon operating mode",
|
|
1063
|
+
fullDescription: `Set the daemon's operating mode:
|
|
1064
|
+
|
|
1065
|
+
- **sprint**: Execute stories from the PRD until all complete (default during active development)
|
|
1066
|
+
- **maintain**: Run recurring routines (security audits, dep updates, test coverage) — no new features
|
|
1067
|
+
- **grow**: Re-evaluate the project vision and generate strategic stories for the next sprint
|
|
1068
|
+
- **auto**: Automatically transition between modes based on project state (recommended)
|
|
1069
|
+
|
|
1070
|
+
In auto mode, the lifecycle is: sprint → maintain → grow → sprint (repeating)`,
|
|
1071
|
+
inputSchema: z.object({
|
|
1072
|
+
mode: z.enum(["sprint", "maintain", "grow", "auto"]).describe("Operating mode"),
|
|
1073
|
+
}),
|
|
1074
|
+
handler: async ({ mode }, ctx) => {
|
|
1075
|
+
saveConfig(ctx.projectPath, { mode: mode });
|
|
1076
|
+
ctx.chatManager.writeMessage({
|
|
1077
|
+
agent: "NightShift",
|
|
1078
|
+
type: "INFO",
|
|
1079
|
+
content: `Operating mode set to: ${mode}`,
|
|
1080
|
+
});
|
|
1081
|
+
return {
|
|
1082
|
+
content: [{
|
|
1083
|
+
type: "text",
|
|
1084
|
+
text: JSON.stringify({
|
|
1085
|
+
mode,
|
|
1086
|
+
message: `Operating mode set to "${mode}"`,
|
|
1087
|
+
description: {
|
|
1088
|
+
sprint: "Execute stories until PRD is complete",
|
|
1089
|
+
maintain: "Run recurring maintenance routines",
|
|
1090
|
+
grow: "Re-evaluate vision, generate new strategic stories",
|
|
1091
|
+
auto: "Auto-transition: sprint → maintain → grow → sprint",
|
|
1092
|
+
}[mode],
|
|
1093
|
+
}, null, 2),
|
|
1094
|
+
}],
|
|
1095
|
+
};
|
|
1096
|
+
},
|
|
1097
|
+
});
|
|
1098
|
+
export const getModeTool = defineTool({
|
|
1099
|
+
name: "get_mode",
|
|
1100
|
+
category: "agents",
|
|
1101
|
+
description: "Get the current daemon operating mode",
|
|
1102
|
+
fullDescription: "View the current operating mode and project lifecycle state.",
|
|
1103
|
+
inputSchema: z.object({}),
|
|
1104
|
+
handler: async (_params, ctx) => {
|
|
1105
|
+
const config = loadConfig(ctx.projectPath);
|
|
1106
|
+
const summary = ctx.ralphManager.getCompletionSummary();
|
|
1107
|
+
return {
|
|
1108
|
+
content: [{
|
|
1109
|
+
type: "text",
|
|
1110
|
+
text: JSON.stringify({
|
|
1111
|
+
configuredMode: config.mode,
|
|
1112
|
+
hasVision: !!config.vision,
|
|
1113
|
+
vision: config.vision?.substring(0, 200),
|
|
1114
|
+
hasRoutines: (config.maintain?.routines?.length ?? 0) > 0,
|
|
1115
|
+
routineCount: config.maintain?.routines?.length ?? 0,
|
|
1116
|
+
hasGrowConfig: !!config.grow,
|
|
1117
|
+
stories: {
|
|
1118
|
+
total: summary.total,
|
|
1119
|
+
complete: summary.complete,
|
|
1120
|
+
incomplete: summary.incomplete,
|
|
1121
|
+
percentComplete: summary.percentComplete,
|
|
1122
|
+
},
|
|
1123
|
+
hasSchedule: !!config.schedule,
|
|
1124
|
+
schedule: config.schedule,
|
|
1125
|
+
}, null, 2),
|
|
1126
|
+
}],
|
|
1127
|
+
};
|
|
1128
|
+
},
|
|
1129
|
+
});
|
|
1130
|
+
// ============================================
|
|
1131
|
+
// Routine Tools
|
|
1132
|
+
// ============================================
|
|
1133
|
+
export const listRoutinesTool = defineTool({
|
|
1134
|
+
name: "list_routines",
|
|
1135
|
+
category: "agents",
|
|
1136
|
+
description: "List configured maintenance routines and their status",
|
|
1137
|
+
fullDescription: `View all configured maintenance routines, their schedules, last run times, and health status.
|
|
1138
|
+
|
|
1139
|
+
Routines run during "maintain" mode and handle recurring tasks like security audits,
|
|
1140
|
+
dependency updates, and test coverage improvement.`,
|
|
1141
|
+
inputSchema: z.object({
|
|
1142
|
+
showDefaults: z.boolean().optional().describe("Show built-in default routines that can be added"),
|
|
1143
|
+
}),
|
|
1144
|
+
handler: async ({ showDefaults }, ctx) => {
|
|
1145
|
+
const config = loadConfig(ctx.projectPath);
|
|
1146
|
+
const routines = config.maintain?.routines ?? [];
|
|
1147
|
+
const status = routines.length > 0
|
|
1148
|
+
? getRoutineStatus(routines, ctx.projectPath)
|
|
1149
|
+
: [];
|
|
1150
|
+
const response = {
|
|
1151
|
+
configuredRoutines: status,
|
|
1152
|
+
count: routines.length,
|
|
1153
|
+
};
|
|
1154
|
+
if (showDefaults) {
|
|
1155
|
+
response.availableDefaults = getDefaultRoutines().map(r => ({
|
|
1156
|
+
name: r.name,
|
|
1157
|
+
type: r.type,
|
|
1158
|
+
schedule: r.schedule,
|
|
1159
|
+
agent: r.agent,
|
|
1160
|
+
description: r.prompt.split("\n")[0],
|
|
1161
|
+
}));
|
|
1162
|
+
}
|
|
1163
|
+
if (routines.length === 0) {
|
|
1164
|
+
response.hint = "No routines configured. Use add_routine to add maintenance routines, or pass showDefaults=true to see built-in options.";
|
|
1165
|
+
}
|
|
1166
|
+
return {
|
|
1167
|
+
content: [{ type: "text", text: JSON.stringify(response, null, 2) }],
|
|
1168
|
+
};
|
|
1169
|
+
},
|
|
1170
|
+
});
|
|
1171
|
+
export const addRoutineTool = defineTool({
|
|
1172
|
+
name: "add_routine",
|
|
1173
|
+
category: "agents",
|
|
1174
|
+
description: "Add a maintenance routine",
|
|
1175
|
+
fullDescription: `Add a recurring maintenance routine to the project.
|
|
1176
|
+
|
|
1177
|
+
You can add a built-in default routine by name (e.g., "security-audit", "dependency-updates", "test-coverage")
|
|
1178
|
+
or define a custom routine with a name, schedule, agent, and prompt.
|
|
1179
|
+
|
|
1180
|
+
Routines run during "maintain" mode after all sprint stories are complete.`,
|
|
1181
|
+
inputSchema: z.object({
|
|
1182
|
+
name: z.string().describe("Routine name (use a default name like 'security-audit' to add a built-in routine)"),
|
|
1183
|
+
schedule: z.enum(["hourly", "daily", "weekly", "monthly"]).optional().describe("How often to run (default: from built-in or 'daily')"),
|
|
1184
|
+
agent: z.string().optional().describe("Agent to execute (default: from built-in or 'gemini')"),
|
|
1185
|
+
prompt: z.string().optional().describe("Custom prompt (default: from built-in routine if name matches)"),
|
|
1186
|
+
type: z.string().optional().describe("Routine type: audit, maintenance, quality, optimization, monitoring, custom"),
|
|
1187
|
+
}),
|
|
1188
|
+
handler: async (params, ctx) => {
|
|
1189
|
+
const config = loadConfig(ctx.projectPath);
|
|
1190
|
+
const routines = config.maintain?.routines ?? [];
|
|
1191
|
+
// Check for duplicates
|
|
1192
|
+
if (routines.find(r => r.name === params.name)) {
|
|
1193
|
+
return {
|
|
1194
|
+
content: [{ type: "text", text: JSON.stringify({ error: `Routine "${params.name}" already exists` }, null, 2) }],
|
|
1195
|
+
isError: true,
|
|
1196
|
+
};
|
|
1197
|
+
}
|
|
1198
|
+
// Check if it's a built-in default
|
|
1199
|
+
const defaults = getDefaultRoutines();
|
|
1200
|
+
const defaultRoutine = defaults.find(d => d.name === params.name);
|
|
1201
|
+
const newRoutine = defaultRoutine
|
|
1202
|
+
? {
|
|
1203
|
+
...defaultRoutine,
|
|
1204
|
+
schedule: params.schedule ?? defaultRoutine.schedule,
|
|
1205
|
+
agent: (params.agent ?? defaultRoutine.agent),
|
|
1206
|
+
prompt: params.prompt ?? defaultRoutine.prompt,
|
|
1207
|
+
}
|
|
1208
|
+
: {
|
|
1209
|
+
name: params.name,
|
|
1210
|
+
schedule: params.schedule ?? "daily",
|
|
1211
|
+
agent: (params.agent ?? "gemini"),
|
|
1212
|
+
prompt: params.prompt ?? `Run the "${params.name}" routine for this project.`,
|
|
1213
|
+
type: (params.type ?? "custom"),
|
|
1214
|
+
timeout: 600,
|
|
1215
|
+
};
|
|
1216
|
+
routines.push(newRoutine);
|
|
1217
|
+
saveConfig(ctx.projectPath, { maintain: { routines } });
|
|
1218
|
+
return {
|
|
1219
|
+
content: [{
|
|
1220
|
+
type: "text",
|
|
1221
|
+
text: JSON.stringify({
|
|
1222
|
+
success: true,
|
|
1223
|
+
routine: { name: newRoutine.name, schedule: newRoutine.schedule, agent: newRoutine.agent, type: newRoutine.type },
|
|
1224
|
+
message: `Routine "${newRoutine.name}" added (${newRoutine.schedule}, ${newRoutine.agent})`,
|
|
1225
|
+
totalRoutines: routines.length,
|
|
1226
|
+
}, null, 2),
|
|
1227
|
+
}],
|
|
1228
|
+
};
|
|
1229
|
+
},
|
|
1230
|
+
});
|
|
1231
|
+
export const resetRoutineTool = defineTool({
|
|
1232
|
+
name: "reset_routine",
|
|
1233
|
+
category: "agents",
|
|
1234
|
+
description: "Reset a routine's failure count (re-enable after circuit break)",
|
|
1235
|
+
fullDescription: "Reset a routine that has been disabled after 3 consecutive failures. This clears the failure count and allows it to run again.",
|
|
1236
|
+
inputSchema: z.object({
|
|
1237
|
+
name: z.string().describe("Name of the routine to reset"),
|
|
1238
|
+
}),
|
|
1239
|
+
handler: async ({ name }, ctx) => {
|
|
1240
|
+
const success = resetRoutine(ctx.projectPath, name);
|
|
1241
|
+
return {
|
|
1242
|
+
content: [{
|
|
1243
|
+
type: "text",
|
|
1244
|
+
text: JSON.stringify({
|
|
1245
|
+
success,
|
|
1246
|
+
message: success ? `Routine "${name}" reset — will run on next cycle` : `Routine "${name}" not found in state`,
|
|
1247
|
+
}, null, 2),
|
|
1248
|
+
}],
|
|
1249
|
+
};
|
|
1250
|
+
},
|
|
1251
|
+
});
|
|
966
1252
|
export const agentTools = [
|
|
967
1253
|
listAvailableAgents,
|
|
968
1254
|
spawnAgentTool,
|
|
@@ -977,5 +1263,13 @@ export const agentTools = [
|
|
|
977
1263
|
getRunStatsTool,
|
|
978
1264
|
getPipelineTool,
|
|
979
1265
|
setPipelineTool,
|
|
1266
|
+
setScheduleTool,
|
|
1267
|
+
getScheduleTool,
|
|
1268
|
+
removeScheduleTool,
|
|
1269
|
+
setModeTool,
|
|
1270
|
+
getModeTool,
|
|
1271
|
+
listRoutinesTool,
|
|
1272
|
+
addRoutineTool,
|
|
1273
|
+
resetRoutineTool,
|
|
980
1274
|
];
|
|
981
1275
|
//# sourceMappingURL=agents.js.map
|