@lovelybunch/api 1.0.69-alpha.2 → 1.0.69-alpha.3
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/dist/lib/jobs/job-runner.d.ts +3 -0
- package/dist/lib/jobs/job-runner.js +84 -9
- package/package.json +4 -4
- package/static/assets/{index-H3StNuPn.js → index-D3PxQUiY.js} +144 -144
- package/static/assets/index-ZOkx8dA0.css +33 -0
- package/static/index.html +2 -2
- package/static/assets/index-BPocBO74.css +0 -33
|
@@ -12,6 +12,9 @@ export declare class JobRunner {
|
|
|
12
12
|
private ensureCliAvailable;
|
|
13
13
|
private ensureLogPath;
|
|
14
14
|
private loadAgentInstructions;
|
|
15
|
+
private loadMcpConfigs;
|
|
16
|
+
private writeMcpJson;
|
|
17
|
+
private cleanupMcpJson;
|
|
15
18
|
private buildInstruction;
|
|
16
19
|
run(job: ScheduledJob, runId: string): Promise<JobRunResult>;
|
|
17
20
|
}
|
|
@@ -20,29 +20,37 @@ function resolveAgent(model) {
|
|
|
20
20
|
}
|
|
21
21
|
function buildCommand(agent, instruction, config) {
|
|
22
22
|
const quotedInstruction = shellQuote(instruction);
|
|
23
|
-
|
|
24
|
-
? config.mcpServers.map(server => `--mcp ${shellQuote(server)}`).join(' ')
|
|
25
|
-
: '';
|
|
23
|
+
let mainCommand = '';
|
|
26
24
|
switch (agent) {
|
|
27
25
|
case 'gemini': {
|
|
28
|
-
|
|
29
|
-
|
|
26
|
+
// For non-Claude agents, use the --mcp flag approach if supported
|
|
27
|
+
const mcpFlags = config.mcpServers && config.mcpServers.length > 0
|
|
28
|
+
? config.mcpServers.map(server => `--mcp ${shellQuote(server)}`).join(' ')
|
|
29
|
+
: '';
|
|
30
|
+
mainCommand = `gemini --yolo ${mcpFlags} -i ${quotedInstruction}`;
|
|
31
|
+
break;
|
|
30
32
|
}
|
|
31
33
|
case 'codex': {
|
|
34
|
+
// For non-Claude agents, use the --mcp flag approach if supported
|
|
35
|
+
const mcpFlags = config.mcpServers && config.mcpServers.length > 0
|
|
36
|
+
? config.mcpServers.map(server => `--mcp ${shellQuote(server)}`).join(' ')
|
|
37
|
+
: '';
|
|
32
38
|
const baseCmd = `codex ${quotedInstruction} --dangerously-bypass-approvals-and-sandbox ${mcpFlags}`.trim();
|
|
33
39
|
const needsPseudoTty = config.runningAsRoot && process.platform !== 'win32';
|
|
34
|
-
|
|
40
|
+
mainCommand = needsPseudoTty
|
|
35
41
|
? `script -q -e -c ${shellQuote(baseCmd)} /dev/null`
|
|
36
42
|
: baseCmd;
|
|
37
|
-
|
|
43
|
+
break;
|
|
38
44
|
}
|
|
39
45
|
case 'claude':
|
|
40
46
|
default: {
|
|
47
|
+
// Claude uses .mcp.json for MCP server configuration (no --mcp flag)
|
|
41
48
|
const prefix = config.runningAsRoot ? 'IS_SANDBOX=1 ' : '';
|
|
42
|
-
|
|
43
|
-
|
|
49
|
+
mainCommand = `${prefix}claude ${quotedInstruction} --dangerously-skip-permissions`.trim();
|
|
50
|
+
break;
|
|
44
51
|
}
|
|
45
52
|
}
|
|
53
|
+
return { command: agent === 'claude' ? 'claude' : agent, shellCommand: mainCommand };
|
|
46
54
|
}
|
|
47
55
|
const CLI_AGENT_LABEL = {
|
|
48
56
|
claude: 'Claude',
|
|
@@ -100,6 +108,52 @@ export class JobRunner {
|
|
|
100
108
|
return null;
|
|
101
109
|
}
|
|
102
110
|
}
|
|
111
|
+
async loadMcpConfigs() {
|
|
112
|
+
try {
|
|
113
|
+
const projectRoot = await this.projectRootPromise;
|
|
114
|
+
const mcpConfigPath = path.join(projectRoot, '.nut', 'mcp', 'config.json');
|
|
115
|
+
const content = await fs.readFile(mcpConfigPath, 'utf-8');
|
|
116
|
+
const json = JSON.parse(content);
|
|
117
|
+
return json.mcpServers || {};
|
|
118
|
+
}
|
|
119
|
+
catch (error) {
|
|
120
|
+
if (error.code !== 'ENOENT') {
|
|
121
|
+
console.warn('Failed to load MCP config:', error);
|
|
122
|
+
}
|
|
123
|
+
return {};
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
async writeMcpJson(mcpServers, allMcpConfigs) {
|
|
127
|
+
const projectRoot = await this.projectRootPromise;
|
|
128
|
+
const mcpJsonPath = path.join(projectRoot, '.mcp.json');
|
|
129
|
+
// Filter to only include the requested servers that are enabled
|
|
130
|
+
const filteredConfigs = {};
|
|
131
|
+
for (const serverName of mcpServers) {
|
|
132
|
+
const config = allMcpConfigs[serverName];
|
|
133
|
+
if (config && config.enabled !== false) {
|
|
134
|
+
filteredConfigs[serverName] = config;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
const mcpJson = {
|
|
138
|
+
mcpServers: filteredConfigs
|
|
139
|
+
};
|
|
140
|
+
await fs.writeFile(mcpJsonPath, JSON.stringify(mcpJson, null, 2), 'utf-8');
|
|
141
|
+
}
|
|
142
|
+
async cleanupMcpJson() {
|
|
143
|
+
try {
|
|
144
|
+
const projectRoot = await this.projectRootPromise;
|
|
145
|
+
const mcpJsonPath = path.join(projectRoot, '.mcp.json');
|
|
146
|
+
// Reset to empty mcpServers object
|
|
147
|
+
const emptyMcpJson = {
|
|
148
|
+
mcpServers: {}
|
|
149
|
+
};
|
|
150
|
+
await fs.writeFile(mcpJsonPath, JSON.stringify(emptyMcpJson, null, 2), 'utf-8');
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
// Don't fail the job if cleanup fails
|
|
154
|
+
console.warn('Failed to cleanup .mcp.json:', error);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
103
157
|
async buildInstruction(job, agentLabel) {
|
|
104
158
|
const scheduleDescription = job.schedule.type === 'cron'
|
|
105
159
|
? `Cron: ${job.schedule.expression}`
|
|
@@ -124,6 +178,12 @@ export class JobRunner {
|
|
|
124
178
|
const agent = resolveAgent(job.model);
|
|
125
179
|
const instruction = await this.buildInstruction(job, CLI_AGENT_LABEL[agent] || agent);
|
|
126
180
|
const runningAsRoot = typeof process.getuid === 'function' && process.getuid() === 0;
|
|
181
|
+
// Write .mcp.json if MCP servers are specified (Claude reads this from project root)
|
|
182
|
+
const mcpJsonWritten = job.mcpServers && job.mcpServers.length > 0 && agent === 'claude';
|
|
183
|
+
if (mcpJsonWritten) {
|
|
184
|
+
const allMcpConfigs = await this.loadMcpConfigs();
|
|
185
|
+
await this.writeMcpJson(job.mcpServers, allMcpConfigs);
|
|
186
|
+
}
|
|
127
187
|
const { shellCommand } = buildCommand(agent, instruction, {
|
|
128
188
|
runningAsRoot,
|
|
129
189
|
mcpServers: job.mcpServers
|
|
@@ -135,6 +195,9 @@ export class JobRunner {
|
|
|
135
195
|
logStream.write(`[${new Date().toISOString()}] Starting job ${job.id} using ${agent} CLI\n`);
|
|
136
196
|
logStream.write(`Instruction: ${instruction}\n`);
|
|
137
197
|
logStream.write(`Command: ${shellCommand}\n`);
|
|
198
|
+
if (job.mcpServers && job.mcpServers.length > 0) {
|
|
199
|
+
logStream.write(`MCP Servers: ${job.mcpServers.join(', ')} (configured via .mcp.json)\n`);
|
|
200
|
+
}
|
|
138
201
|
return new Promise((resolve) => {
|
|
139
202
|
let cliMissingError = null;
|
|
140
203
|
try {
|
|
@@ -147,6 +210,10 @@ export class JobRunner {
|
|
|
147
210
|
const message = cliMissingError.message;
|
|
148
211
|
logStream.write(`${message}\n`);
|
|
149
212
|
logStream.end();
|
|
213
|
+
// Cleanup .mcp.json if it was written
|
|
214
|
+
if (mcpJsonWritten) {
|
|
215
|
+
this.cleanupMcpJson().catch(err => console.warn('Cleanup failed:', err));
|
|
216
|
+
}
|
|
150
217
|
resolve({
|
|
151
218
|
status: 'failed',
|
|
152
219
|
error: message,
|
|
@@ -182,6 +249,10 @@ export class JobRunner {
|
|
|
182
249
|
logStream.write(`${message}\n`);
|
|
183
250
|
logStream.end();
|
|
184
251
|
clearTimeout(abortTimeout);
|
|
252
|
+
// Cleanup .mcp.json if it was written
|
|
253
|
+
if (mcpJsonWritten) {
|
|
254
|
+
this.cleanupMcpJson().catch(err => console.warn('Cleanup failed:', err));
|
|
255
|
+
}
|
|
185
256
|
resolve({
|
|
186
257
|
status: 'failed',
|
|
187
258
|
error: message,
|
|
@@ -195,6 +266,10 @@ export class JobRunner {
|
|
|
195
266
|
logStream.write(`\n[${new Date().toISOString()}] Job ${job.id} completed with exit code ${code}\n`);
|
|
196
267
|
logStream.end();
|
|
197
268
|
clearTimeout(abortTimeout);
|
|
269
|
+
// Cleanup .mcp.json if it was written
|
|
270
|
+
if (mcpJsonWritten) {
|
|
271
|
+
this.cleanupMcpJson().catch(err => console.warn('Cleanup failed:', err));
|
|
272
|
+
}
|
|
198
273
|
const summary = summaryChunks.join('');
|
|
199
274
|
resolve({
|
|
200
275
|
status,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovelybunch/api",
|
|
3
|
-
"version": "1.0.69-alpha.
|
|
3
|
+
"version": "1.0.69-alpha.3",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/server-with-static.js",
|
|
6
6
|
"exports": {
|
|
@@ -36,9 +36,9 @@
|
|
|
36
36
|
"dependencies": {
|
|
37
37
|
"@hono/node-server": "^1.13.7",
|
|
38
38
|
"@hono/node-ws": "^1.0.6",
|
|
39
|
-
"@lovelybunch/core": "^1.0.69-alpha.
|
|
40
|
-
"@lovelybunch/mcp": "^1.0.69-alpha.
|
|
41
|
-
"@lovelybunch/types": "^1.0.69-alpha.
|
|
39
|
+
"@lovelybunch/core": "^1.0.69-alpha.3",
|
|
40
|
+
"@lovelybunch/mcp": "^1.0.69-alpha.3",
|
|
41
|
+
"@lovelybunch/types": "^1.0.69-alpha.3",
|
|
42
42
|
"arctic": "^1.9.2",
|
|
43
43
|
"bcrypt": "^5.1.1",
|
|
44
44
|
"cookie": "^0.6.0",
|