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.
@@ -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"}
@@ -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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"}
@@ -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":"AA2EA,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;AAGH,eAAO,MAAM,UAAU,gDActB,CAAC"}
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"}
@@ -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