bernard-agent 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +21 -0
- package/LICENSE +21 -0
- package/README.md +629 -0
- package/dist/agent.d.ts +24 -0
- package/dist/agent.js +174 -0
- package/dist/agent.js.map +1 -0
- package/dist/config.d.ts +44 -0
- package/dist/config.js +267 -0
- package/dist/config.js.map +1 -0
- package/dist/context.d.ts +37 -0
- package/dist/context.js +245 -0
- package/dist/context.js.map +1 -0
- package/dist/cron/client.d.ts +4 -0
- package/dist/cron/client.js +113 -0
- package/dist/cron/client.js.map +1 -0
- package/dist/cron/daemon.d.ts +1 -0
- package/dist/cron/daemon.js +132 -0
- package/dist/cron/daemon.js.map +1 -0
- package/dist/cron/log-store.d.ts +51 -0
- package/dist/cron/log-store.js +135 -0
- package/dist/cron/log-store.js.map +1 -0
- package/dist/cron/notify.d.ts +7 -0
- package/dist/cron/notify.js +136 -0
- package/dist/cron/notify.js.map +1 -0
- package/dist/cron/runner.d.ts +6 -0
- package/dist/cron/runner.js +219 -0
- package/dist/cron/runner.js.map +1 -0
- package/dist/cron/scheduler.d.ts +16 -0
- package/dist/cron/scheduler.js +105 -0
- package/dist/cron/scheduler.js.map +1 -0
- package/dist/cron/store.d.ts +20 -0
- package/dist/cron/store.js +170 -0
- package/dist/cron/store.js.map +1 -0
- package/dist/cron/types.d.ts +21 -0
- package/dist/cron/types.js +3 -0
- package/dist/cron/types.js.map +1 -0
- package/dist/embeddings.d.ts +14 -0
- package/dist/embeddings.js +61 -0
- package/dist/embeddings.js.map +1 -0
- package/dist/history.d.ts +6 -0
- package/dist/history.js +71 -0
- package/dist/history.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +231 -0
- package/dist/index.js.map +1 -0
- package/dist/logger.d.ts +1 -0
- package/dist/logger.js +24 -0
- package/dist/logger.js.map +1 -0
- package/dist/mcp.d.ts +43 -0
- package/dist/mcp.js +303 -0
- package/dist/mcp.js.map +1 -0
- package/dist/memory.d.ts +17 -0
- package/dist/memory.js +106 -0
- package/dist/memory.js.map +1 -0
- package/dist/output.d.ts +13 -0
- package/dist/output.js +151 -0
- package/dist/output.js.map +1 -0
- package/dist/providers/index.d.ts +2 -0
- package/dist/providers/index.js +19 -0
- package/dist/providers/index.js.map +1 -0
- package/dist/providers/types.d.ts +5 -0
- package/dist/providers/types.js +3 -0
- package/dist/providers/types.js.map +1 -0
- package/dist/rag-worker.d.ts +10 -0
- package/dist/rag-worker.js +84 -0
- package/dist/rag-worker.js.map +1 -0
- package/dist/rag.d.ts +53 -0
- package/dist/rag.js +242 -0
- package/dist/rag.js.map +1 -0
- package/dist/repl.d.ts +2 -0
- package/dist/repl.js +531 -0
- package/dist/repl.js.map +1 -0
- package/dist/setup.d.ts +1 -0
- package/dist/setup.js +104 -0
- package/dist/setup.js.map +1 -0
- package/dist/tools/cron-logs.d.ts +67 -0
- package/dist/tools/cron-logs.js +131 -0
- package/dist/tools/cron-logs.js.map +1 -0
- package/dist/tools/cron.d.ts +98 -0
- package/dist/tools/cron.js +248 -0
- package/dist/tools/cron.js.map +1 -0
- package/dist/tools/datetime.d.ts +4 -0
- package/dist/tools/datetime.js +25 -0
- package/dist/tools/datetime.js.map +1 -0
- package/dist/tools/index.d.ts +317 -0
- package/dist/tools/index.js +28 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/mcp-url.d.ts +16 -0
- package/dist/tools/mcp-url.js +27 -0
- package/dist/tools/mcp-url.js.map +1 -0
- package/dist/tools/mcp.d.ts +28 -0
- package/dist/tools/mcp.js +107 -0
- package/dist/tools/mcp.js.map +1 -0
- package/dist/tools/memory.d.ts +40 -0
- package/dist/tools/memory.js +99 -0
- package/dist/tools/memory.js.map +1 -0
- package/dist/tools/shell.d.ts +15 -0
- package/dist/tools/shell.js +60 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/tools/subagent.d.ts +21 -0
- package/dist/tools/subagent.js +81 -0
- package/dist/tools/subagent.js.map +1 -0
- package/dist/tools/time.d.ts +50 -0
- package/dist/tools/time.js +61 -0
- package/dist/tools/time.js.map +1 -0
- package/dist/tools/types.d.ts +8 -0
- package/dist/tools/types.js +3 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/tools/web.d.ts +16 -0
- package/dist/tools/web.js +136 -0
- package/dist/tools/web.js.map +1 -0
- package/package.json +73 -0
package/dist/context.js
ADDED
|
@@ -0,0 +1,245 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RECENT_TURNS_TO_KEEP = exports.COMPRESSION_THRESHOLD = exports.DEFAULT_CONTEXT_WINDOW = exports.MODEL_CONTEXT_WINDOWS = void 0;
|
|
4
|
+
exports.getContextWindow = getContextWindow;
|
|
5
|
+
exports.shouldCompress = shouldCompress;
|
|
6
|
+
exports.serializeMessages = serializeMessages;
|
|
7
|
+
exports.countRecentMessages = countRecentMessages;
|
|
8
|
+
exports.extractFacts = extractFacts;
|
|
9
|
+
exports.compressHistory = compressHistory;
|
|
10
|
+
const ai_1 = require("ai");
|
|
11
|
+
const index_js_1 = require("./providers/index.js");
|
|
12
|
+
const logger_js_1 = require("./logger.js");
|
|
13
|
+
/** Model name → context window size in tokens */
|
|
14
|
+
exports.MODEL_CONTEXT_WINDOWS = {
|
|
15
|
+
// Anthropic
|
|
16
|
+
'claude-sonnet-4-5-20250929': 200_000,
|
|
17
|
+
'claude-opus-4-20250514': 200_000,
|
|
18
|
+
'claude-sonnet-4-20250514': 200_000,
|
|
19
|
+
'claude-3-5-haiku-latest': 200_000,
|
|
20
|
+
// OpenAI
|
|
21
|
+
'gpt-4o': 128_000,
|
|
22
|
+
'gpt-4o-mini': 128_000,
|
|
23
|
+
'o3': 200_000,
|
|
24
|
+
'o3-mini': 200_000,
|
|
25
|
+
'o4-mini': 200_000,
|
|
26
|
+
'gpt-4.1': 1_000_000,
|
|
27
|
+
'gpt-4.1-mini': 1_000_000,
|
|
28
|
+
'gpt-4.1-nano': 1_000_000,
|
|
29
|
+
// xAI
|
|
30
|
+
'grok-3': 131_072,
|
|
31
|
+
'grok-3-fast': 131_072,
|
|
32
|
+
'grok-3-mini': 131_072,
|
|
33
|
+
'grok-3-mini-fast': 131_072,
|
|
34
|
+
};
|
|
35
|
+
exports.DEFAULT_CONTEXT_WINDOW = 128_000;
|
|
36
|
+
exports.COMPRESSION_THRESHOLD = 0.75;
|
|
37
|
+
exports.RECENT_TURNS_TO_KEEP = 4;
|
|
38
|
+
/** Look up context window for a model, falling back to 128k for unknown models. */
|
|
39
|
+
function getContextWindow(model) {
|
|
40
|
+
return exports.MODEL_CONTEXT_WINDOWS[model] ?? exports.DEFAULT_CONTEXT_WINDOW;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Returns true when estimated token usage exceeds the compression threshold.
|
|
44
|
+
* @param lastPromptTokens - actual prompt token count from the last API call
|
|
45
|
+
* @param newMessageEstimate - rough token estimate for the new user message
|
|
46
|
+
* @param model - model name for context window lookup
|
|
47
|
+
*/
|
|
48
|
+
function shouldCompress(lastPromptTokens, newMessageEstimate, model) {
|
|
49
|
+
const contextWindow = getContextWindow(model);
|
|
50
|
+
const estimated = lastPromptTokens + newMessageEstimate;
|
|
51
|
+
return estimated > contextWindow * exports.COMPRESSION_THRESHOLD;
|
|
52
|
+
}
|
|
53
|
+
/** Convert a CoreMessage array into readable text for the summarizer. */
|
|
54
|
+
function serializeMessages(messages) {
|
|
55
|
+
const lines = [];
|
|
56
|
+
for (const msg of messages) {
|
|
57
|
+
if (msg.role === 'user') {
|
|
58
|
+
const text = extractText(msg);
|
|
59
|
+
if (text)
|
|
60
|
+
lines.push(`User: ${text}`);
|
|
61
|
+
}
|
|
62
|
+
else if (msg.role === 'assistant') {
|
|
63
|
+
const text = extractText(msg);
|
|
64
|
+
if (text)
|
|
65
|
+
lines.push(`Assistant: ${text}`);
|
|
66
|
+
// Include tool calls if present
|
|
67
|
+
if (Array.isArray(msg.content)) {
|
|
68
|
+
for (const part of msg.content) {
|
|
69
|
+
if (typeof part === 'object' && part !== null && 'type' in part && part.type === 'tool-call') {
|
|
70
|
+
const tc = part;
|
|
71
|
+
lines.push(`Assistant [tool call]: ${tc.toolName}(${JSON.stringify(tc.args)})`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
else if (msg.role === 'tool') {
|
|
77
|
+
// Tool results
|
|
78
|
+
if (Array.isArray(msg.content)) {
|
|
79
|
+
for (const part of msg.content) {
|
|
80
|
+
if (typeof part === 'object' && part !== null && 'type' in part && part.type === 'tool-result') {
|
|
81
|
+
const tr = part;
|
|
82
|
+
const name = tr.toolName ?? 'tool';
|
|
83
|
+
const resultStr = typeof tr.result === 'string' ? tr.result : JSON.stringify(tr.result);
|
|
84
|
+
const truncated = resultStr.length > 500 ? resultStr.slice(0, 500) + '...' : resultStr;
|
|
85
|
+
lines.push(`Tool [${name}]: ${truncated}`);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
return lines.join('\n');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Walk backward through history to find the split point that keeps the last N
|
|
95
|
+
* user/assistant exchanges intact.
|
|
96
|
+
* Returns the index where "recent" messages start (0 means nothing to compress).
|
|
97
|
+
*/
|
|
98
|
+
function countRecentMessages(history, turnsToKeep) {
|
|
99
|
+
let userTurns = 0;
|
|
100
|
+
for (let i = history.length - 1; i >= 0; i--) {
|
|
101
|
+
if (history[i].role === 'user') {
|
|
102
|
+
userTurns++;
|
|
103
|
+
if (userTurns === turnsToKeep) {
|
|
104
|
+
// If this is already the start, there's nothing older to compress
|
|
105
|
+
if (i === 0)
|
|
106
|
+
return 0;
|
|
107
|
+
return i;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
// Fewer user turns than turnsToKeep — nothing to compress
|
|
112
|
+
return 0;
|
|
113
|
+
}
|
|
114
|
+
const FACT_EXTRACTION_PROMPT = `You are a fact extraction system. Extract notable, self-contained facts from the conversation below that would be useful to recall in future sessions.
|
|
115
|
+
|
|
116
|
+
Extract:
|
|
117
|
+
- User preferences and habits
|
|
118
|
+
- Project details, structure, and conventions
|
|
119
|
+
- Technical environment info (OS, languages, tools, versions)
|
|
120
|
+
- Decisions made and their reasoning
|
|
121
|
+
- Recurring patterns or workflows
|
|
122
|
+
- Names, roles, and relationships mentioned
|
|
123
|
+
|
|
124
|
+
Do NOT extract:
|
|
125
|
+
- Task-specific transient details (e.g., "the user asked to fix a typo on line 42")
|
|
126
|
+
- Generic knowledge that any AI would know
|
|
127
|
+
- Greetings, filler, or conversational noise
|
|
128
|
+
|
|
129
|
+
Return a JSON array of strings. Each string should be a self-contained fact (understandable without the original conversation). Maximum 500 characters per fact. If there are no notable facts, return an empty array [].`;
|
|
130
|
+
const FACT_EXTRACTION_MAX = 500;
|
|
131
|
+
/**
|
|
132
|
+
* Extract notable facts from serialized conversation text via LLM.
|
|
133
|
+
* Returns an empty array on any failure.
|
|
134
|
+
* @internal
|
|
135
|
+
*/
|
|
136
|
+
async function extractFacts(serializedText, config) {
|
|
137
|
+
if (!serializedText.trim())
|
|
138
|
+
return [];
|
|
139
|
+
try {
|
|
140
|
+
const result = await (0, ai_1.generateText)({
|
|
141
|
+
model: (0, index_js_1.getModel)(config.provider, config.model),
|
|
142
|
+
maxTokens: 2048,
|
|
143
|
+
system: FACT_EXTRACTION_PROMPT,
|
|
144
|
+
messages: [
|
|
145
|
+
{ role: 'user', content: `Extract facts from this conversation:\n\n${serializedText}` },
|
|
146
|
+
],
|
|
147
|
+
});
|
|
148
|
+
const text = result.text?.trim();
|
|
149
|
+
if (!text)
|
|
150
|
+
return [];
|
|
151
|
+
// Parse JSON array from response — handle markdown code fences
|
|
152
|
+
const jsonStr = text.replace(/^```(?:json)?\s*/m, '').replace(/\s*```$/m, '');
|
|
153
|
+
const parsed = JSON.parse(jsonStr);
|
|
154
|
+
if (!Array.isArray(parsed))
|
|
155
|
+
return [];
|
|
156
|
+
return parsed
|
|
157
|
+
.filter((item) => typeof item === 'string' && item.length > 0)
|
|
158
|
+
.filter((item) => item.length <= FACT_EXTRACTION_MAX);
|
|
159
|
+
}
|
|
160
|
+
catch (err) {
|
|
161
|
+
(0, logger_js_1.debugLog)('context:extractFacts', `Failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
162
|
+
return [];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
const SUMMARIZATION_PROMPT = `You are a conversation summarizer. Produce a concise summary of the conversation below, preserving:
|
|
166
|
+
- Key facts, decisions, and outcomes
|
|
167
|
+
- Important tool results and command outputs
|
|
168
|
+
- Any user preferences or requirements mentioned
|
|
169
|
+
- The overall arc of what was discussed and accomplished
|
|
170
|
+
|
|
171
|
+
Be concise but complete. Use bullet points. Do not include greetings or filler.`;
|
|
172
|
+
/**
|
|
173
|
+
* Compress conversation history by summarizing older messages via the LLM.
|
|
174
|
+
* Keeps the most recent turns intact and replaces older messages with a summary.
|
|
175
|
+
* On failure, returns the original history unchanged.
|
|
176
|
+
*/
|
|
177
|
+
async function compressHistory(history, config, ragStore) {
|
|
178
|
+
const splitIndex = countRecentMessages(history, exports.RECENT_TURNS_TO_KEEP);
|
|
179
|
+
// Not enough history to compress
|
|
180
|
+
if (splitIndex === 0) {
|
|
181
|
+
return history;
|
|
182
|
+
}
|
|
183
|
+
const oldMessages = history.slice(0, splitIndex);
|
|
184
|
+
const recentMessages = history.slice(splitIndex);
|
|
185
|
+
const serialized = serializeMessages(oldMessages);
|
|
186
|
+
if (!serialized.trim()) {
|
|
187
|
+
return history;
|
|
188
|
+
}
|
|
189
|
+
try {
|
|
190
|
+
// Run summarization and fact extraction in parallel
|
|
191
|
+
const summarizePromise = (0, ai_1.generateText)({
|
|
192
|
+
model: (0, index_js_1.getModel)(config.provider, config.model),
|
|
193
|
+
maxTokens: 2048,
|
|
194
|
+
system: SUMMARIZATION_PROMPT,
|
|
195
|
+
messages: [
|
|
196
|
+
{ role: 'user', content: `Summarize this conversation:\n\n${serialized}` },
|
|
197
|
+
],
|
|
198
|
+
});
|
|
199
|
+
const extractPromise = ragStore
|
|
200
|
+
? extractFacts(serialized, config)
|
|
201
|
+
: Promise.resolve([]);
|
|
202
|
+
const [result, facts] = await Promise.all([summarizePromise, extractPromise]);
|
|
203
|
+
// Store extracted facts fire-and-forget
|
|
204
|
+
if (ragStore && facts.length > 0) {
|
|
205
|
+
ragStore.addFacts(facts, 'compression').catch((err) => {
|
|
206
|
+
(0, logger_js_1.debugLog)('context:compress:rag', `Failed to store facts: ${err instanceof Error ? err.message : String(err)}`);
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
const summary = result.text?.trim();
|
|
210
|
+
if (!summary) {
|
|
211
|
+
(0, logger_js_1.debugLog)('context:compress', 'Summary was empty, keeping original history');
|
|
212
|
+
return history;
|
|
213
|
+
}
|
|
214
|
+
const summaryMessage = {
|
|
215
|
+
role: 'user',
|
|
216
|
+
content: `[Context Summary — earlier conversation was compressed]\n\n${summary}`,
|
|
217
|
+
};
|
|
218
|
+
const ackMessage = {
|
|
219
|
+
role: 'assistant',
|
|
220
|
+
content: 'Understood. I have the context from our earlier conversation. Let\'s continue.',
|
|
221
|
+
};
|
|
222
|
+
(0, logger_js_1.debugLog)('context:compress', {
|
|
223
|
+
oldMessageCount: oldMessages.length,
|
|
224
|
+
recentMessageCount: recentMessages.length,
|
|
225
|
+
summaryLength: summary.length,
|
|
226
|
+
factsExtracted: facts.length,
|
|
227
|
+
});
|
|
228
|
+
return [summaryMessage, ackMessage, ...recentMessages];
|
|
229
|
+
}
|
|
230
|
+
catch (err) {
|
|
231
|
+
(0, logger_js_1.debugLog)('context:compress:error', err instanceof Error ? err.message : String(err));
|
|
232
|
+
return history;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
function extractText(msg) {
|
|
236
|
+
if (typeof msg.content === 'string')
|
|
237
|
+
return msg.content;
|
|
238
|
+
if (!Array.isArray(msg.content))
|
|
239
|
+
return null;
|
|
240
|
+
const textParts = msg.content
|
|
241
|
+
.filter((p) => typeof p === 'object' && p !== null && 'type' in p && p.type === 'text')
|
|
242
|
+
.map(p => p.text);
|
|
243
|
+
return textParts.length > 0 ? textParts.join(' ') : null;
|
|
244
|
+
}
|
|
245
|
+
//# sourceMappingURL=context.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.isDaemonRunning = isDaemonRunning;
|
|
37
|
+
exports.getDaemonPid = getDaemonPid;
|
|
38
|
+
exports.startDaemon = startDaemon;
|
|
39
|
+
exports.stopDaemon = stopDaemon;
|
|
40
|
+
const fs = __importStar(require("node:fs"));
|
|
41
|
+
const path = __importStar(require("node:path"));
|
|
42
|
+
const node_child_process_1 = require("node:child_process");
|
|
43
|
+
const store_js_1 = require("./store.js");
|
|
44
|
+
function isDaemonRunning() {
|
|
45
|
+
const pidFile = store_js_1.CronStore.pidFile;
|
|
46
|
+
if (!fs.existsSync(pidFile))
|
|
47
|
+
return false;
|
|
48
|
+
try {
|
|
49
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
50
|
+
if (isNaN(pid)) {
|
|
51
|
+
fs.unlinkSync(pidFile);
|
|
52
|
+
return false;
|
|
53
|
+
}
|
|
54
|
+
// Check if process is alive (signal 0 doesn't kill, just checks)
|
|
55
|
+
process.kill(pid, 0);
|
|
56
|
+
return true;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// Process not running — clean up stale PID file
|
|
60
|
+
try {
|
|
61
|
+
fs.unlinkSync(pidFile);
|
|
62
|
+
}
|
|
63
|
+
catch { }
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function getDaemonPid() {
|
|
68
|
+
const pidFile = store_js_1.CronStore.pidFile;
|
|
69
|
+
if (!fs.existsSync(pidFile))
|
|
70
|
+
return null;
|
|
71
|
+
try {
|
|
72
|
+
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
73
|
+
return isNaN(pid) ? null : pid;
|
|
74
|
+
}
|
|
75
|
+
catch {
|
|
76
|
+
return null;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function startDaemon() {
|
|
80
|
+
if (isDaemonRunning())
|
|
81
|
+
return true;
|
|
82
|
+
const daemonPath = path.resolve(__dirname, 'daemon.js');
|
|
83
|
+
if (!fs.existsSync(daemonPath)) {
|
|
84
|
+
throw new Error(`Daemon script not found at ${daemonPath}. Run "npm run build" first.`);
|
|
85
|
+
}
|
|
86
|
+
const child = (0, node_child_process_1.fork)(daemonPath, [], {
|
|
87
|
+
detached: true,
|
|
88
|
+
stdio: 'ignore',
|
|
89
|
+
});
|
|
90
|
+
child.unref();
|
|
91
|
+
if (child.pid) {
|
|
92
|
+
fs.writeFileSync(store_js_1.CronStore.pidFile, String(child.pid), 'utf-8');
|
|
93
|
+
return true;
|
|
94
|
+
}
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
function stopDaemon() {
|
|
98
|
+
const pid = getDaemonPid();
|
|
99
|
+
if (pid === null)
|
|
100
|
+
return false;
|
|
101
|
+
try {
|
|
102
|
+
process.kill(pid, 'SIGTERM');
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
// Process already dead
|
|
106
|
+
}
|
|
107
|
+
try {
|
|
108
|
+
fs.unlinkSync(store_js_1.CronStore.pidFile);
|
|
109
|
+
}
|
|
110
|
+
catch { }
|
|
111
|
+
return true;
|
|
112
|
+
}
|
|
113
|
+
//# sourceMappingURL=client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/cron/client.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const fs = __importStar(require("node:fs"));
|
|
37
|
+
const store_js_1 = require("./store.js");
|
|
38
|
+
const scheduler_js_1 = require("./scheduler.js");
|
|
39
|
+
const config_js_1 = require("../config.js");
|
|
40
|
+
const MAX_LOG_SIZE = 1_000_000; // 1MB
|
|
41
|
+
function createLogger() {
|
|
42
|
+
const logFile = store_js_1.CronStore.logFile;
|
|
43
|
+
return (msg) => {
|
|
44
|
+
const line = `[${new Date().toISOString()}] ${msg}\n`;
|
|
45
|
+
try {
|
|
46
|
+
// Rotate if log exceeds max size
|
|
47
|
+
try {
|
|
48
|
+
const stat = fs.statSync(logFile);
|
|
49
|
+
if (stat.size > MAX_LOG_SIZE) {
|
|
50
|
+
const rotated = logFile + '.old';
|
|
51
|
+
try {
|
|
52
|
+
fs.unlinkSync(rotated);
|
|
53
|
+
}
|
|
54
|
+
catch { }
|
|
55
|
+
fs.renameSync(logFile, rotated);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// File doesn't exist yet, that's fine
|
|
60
|
+
}
|
|
61
|
+
fs.appendFileSync(logFile, line);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// Can't log, nothing we can do
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function main() {
|
|
69
|
+
const log = createLogger();
|
|
70
|
+
log('Daemon starting');
|
|
71
|
+
// Load config to ensure .env is loaded for API keys
|
|
72
|
+
try {
|
|
73
|
+
(0, config_js_1.loadConfig)();
|
|
74
|
+
}
|
|
75
|
+
catch (err) {
|
|
76
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
77
|
+
log(`Config error: ${message}`);
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
const store = new store_js_1.CronStore();
|
|
81
|
+
const scheduler = new scheduler_js_1.Scheduler(store, log);
|
|
82
|
+
// Write PID file
|
|
83
|
+
fs.writeFileSync(store_js_1.CronStore.pidFile, String(process.pid), 'utf-8');
|
|
84
|
+
log(`PID ${process.pid} written`);
|
|
85
|
+
// Detect stale running jobs from a previous crash
|
|
86
|
+
const jobs = store.loadJobs();
|
|
87
|
+
for (const job of jobs) {
|
|
88
|
+
if (job.lastRunStatus === 'running') {
|
|
89
|
+
log(`Warning: Job "${job.name}" (${job.id}) was in running state at startup — previous daemon may have crashed`);
|
|
90
|
+
store.updateJob(job.id, { lastRunStatus: 'error', lastResult: 'Daemon restarted while job was running' });
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// Initial reconcile
|
|
94
|
+
scheduler.reconcile();
|
|
95
|
+
log(`Initial reconcile done. ${scheduler.activeCount} tasks scheduled.`);
|
|
96
|
+
// Watch cron directory for changes (watching the file directly breaks
|
|
97
|
+
// on Linux after atomic writes replace the inode via rename)
|
|
98
|
+
let debounceTimer = null;
|
|
99
|
+
try {
|
|
100
|
+
fs.watch(store_js_1.CronStore.cronDir, (eventType, filename) => {
|
|
101
|
+
if (filename !== 'jobs.json' && filename !== 'jobs.json.tmp')
|
|
102
|
+
return;
|
|
103
|
+
if (debounceTimer)
|
|
104
|
+
clearTimeout(debounceTimer);
|
|
105
|
+
debounceTimer = setTimeout(() => {
|
|
106
|
+
log('jobs.json changed, reconciling');
|
|
107
|
+
scheduler.reconcile();
|
|
108
|
+
log(`Reconcile done. ${scheduler.activeCount} tasks scheduled.`);
|
|
109
|
+
}, 500);
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
catch (err) {
|
|
113
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
114
|
+
log(`Warning: Could not watch cron directory: ${message}. Changes won't be detected until restart.`);
|
|
115
|
+
}
|
|
116
|
+
// Graceful shutdown
|
|
117
|
+
const shutdown = (signal) => {
|
|
118
|
+
log(`Received ${signal}, shutting down`);
|
|
119
|
+
scheduler.stopAll();
|
|
120
|
+
try {
|
|
121
|
+
fs.unlinkSync(store_js_1.CronStore.pidFile);
|
|
122
|
+
}
|
|
123
|
+
catch { }
|
|
124
|
+
log('Daemon stopped');
|
|
125
|
+
process.exit(0);
|
|
126
|
+
};
|
|
127
|
+
process.on('SIGTERM', () => shutdown('SIGTERM'));
|
|
128
|
+
process.on('SIGINT', () => shutdown('SIGINT'));
|
|
129
|
+
log('Daemon running');
|
|
130
|
+
}
|
|
131
|
+
main();
|
|
132
|
+
//# sourceMappingURL=daemon.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"daemon.js","sourceRoot":"","sources":["../../src/cron/daemon.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export interface CronLogStep {
|
|
2
|
+
stepIndex: number;
|
|
3
|
+
timestamp: string;
|
|
4
|
+
text: string;
|
|
5
|
+
toolCalls: Array<{
|
|
6
|
+
toolName: string;
|
|
7
|
+
toolCallId: string;
|
|
8
|
+
args: Record<string, unknown>;
|
|
9
|
+
}>;
|
|
10
|
+
toolResults: Array<{
|
|
11
|
+
toolName: string;
|
|
12
|
+
toolCallId: string;
|
|
13
|
+
result: unknown;
|
|
14
|
+
}>;
|
|
15
|
+
usage: {
|
|
16
|
+
promptTokens: number;
|
|
17
|
+
completionTokens: number;
|
|
18
|
+
totalTokens: number;
|
|
19
|
+
};
|
|
20
|
+
finishReason: string;
|
|
21
|
+
}
|
|
22
|
+
export interface CronLogEntry {
|
|
23
|
+
runId: string;
|
|
24
|
+
jobId: string;
|
|
25
|
+
jobName: string;
|
|
26
|
+
prompt: string;
|
|
27
|
+
startedAt: string;
|
|
28
|
+
completedAt: string;
|
|
29
|
+
durationMs: number;
|
|
30
|
+
success: boolean;
|
|
31
|
+
error?: string;
|
|
32
|
+
finalOutput: string;
|
|
33
|
+
steps: CronLogStep[];
|
|
34
|
+
totalUsage: {
|
|
35
|
+
promptTokens: number;
|
|
36
|
+
completionTokens: number;
|
|
37
|
+
totalTokens: number;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
export declare class CronLogStore {
|
|
41
|
+
constructor();
|
|
42
|
+
static get logsDir(): string;
|
|
43
|
+
private logPath;
|
|
44
|
+
appendEntry(entry: CronLogEntry): void;
|
|
45
|
+
getEntries(jobId: string, limit?: number, offset?: number): CronLogEntry[];
|
|
46
|
+
getEntry(jobId: string, runId: string): CronLogEntry | undefined;
|
|
47
|
+
listJobIds(): string[];
|
|
48
|
+
getEntryCount(jobId: string): number;
|
|
49
|
+
rotate(jobId: string, keep?: number): void;
|
|
50
|
+
deleteJobLogs(jobId: string): boolean;
|
|
51
|
+
}
|