@lovelybunch/api 1.0.59 → 1.0.61
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.js +11 -5
- package/dist/routes/api/v1/agents/[id]/route.js +27 -2
- package/dist/routes/api/v1/agents/route.js +35 -8
- package/package.json +4 -4
- package/static/assets/{index-QHnHUcsV.js → index-ChC_9V5G.js} +205 -195
- package/static/assets/index-zWmbz-pk.css +33 -0
- package/static/index.html +2 -2
- package/static/assets/index-CHq6mL1J.css +0 -33
|
@@ -18,7 +18,7 @@ function resolveAgent(model) {
|
|
|
18
18
|
return 'codex';
|
|
19
19
|
return 'claude';
|
|
20
20
|
}
|
|
21
|
-
function buildCommand(agent, instruction) {
|
|
21
|
+
function buildCommand(agent, instruction, options) {
|
|
22
22
|
const quotedInstruction = shellQuote(instruction);
|
|
23
23
|
switch (agent) {
|
|
24
24
|
case 'gemini': {
|
|
@@ -26,12 +26,17 @@ function buildCommand(agent, instruction) {
|
|
|
26
26
|
return { command: 'gemini', shellCommand: cmd };
|
|
27
27
|
}
|
|
28
28
|
case 'codex': {
|
|
29
|
-
const
|
|
30
|
-
|
|
29
|
+
const baseCmd = `codex ${quotedInstruction} --dangerously-bypass-approvals-and-sandbox`;
|
|
30
|
+
const needsPseudoTty = options.runningAsRoot && process.platform !== 'win32';
|
|
31
|
+
const wrappedCmd = needsPseudoTty
|
|
32
|
+
? `script -q -e -c ${shellQuote(baseCmd)} /dev/null`
|
|
33
|
+
: baseCmd;
|
|
34
|
+
return { command: 'codex', shellCommand: wrappedCmd };
|
|
31
35
|
}
|
|
32
36
|
case 'claude':
|
|
33
37
|
default: {
|
|
34
|
-
const
|
|
38
|
+
const prefix = options.runningAsRoot ? 'IS_SANDBOX=1 ' : '';
|
|
39
|
+
const cmd = `${prefix}claude ${quotedInstruction} --dangerously-skip-permissions`;
|
|
35
40
|
return { command: 'claude', shellCommand: cmd };
|
|
36
41
|
}
|
|
37
42
|
}
|
|
@@ -85,7 +90,8 @@ export class JobRunner {
|
|
|
85
90
|
async run(job, runId) {
|
|
86
91
|
const agent = resolveAgent(job.model);
|
|
87
92
|
const instruction = this.buildInstruction(job, CLI_AGENT_LABEL[agent] || agent);
|
|
88
|
-
const
|
|
93
|
+
const runningAsRoot = typeof process.getuid === 'function' && process.getuid() === 0;
|
|
94
|
+
const { shellCommand } = buildCommand(agent, instruction, { runningAsRoot });
|
|
89
95
|
const projectRoot = await this.projectRootPromise;
|
|
90
96
|
const logPath = await this.ensureLogPath(job.id, runId);
|
|
91
97
|
const logStream = createWriteStream(logPath, { flags: 'a' });
|
|
@@ -3,6 +3,24 @@ import { promises as fs } from 'fs';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import matter from 'gray-matter';
|
|
5
5
|
const app = new Hono();
|
|
6
|
+
function normalizeTools(value) {
|
|
7
|
+
if (!value)
|
|
8
|
+
return undefined;
|
|
9
|
+
if (Array.isArray(value)) {
|
|
10
|
+
const cleaned = value
|
|
11
|
+
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
|
12
|
+
.filter((item) => Boolean(item));
|
|
13
|
+
return cleaned.length > 0 ? Array.from(new Set(cleaned)) : undefined;
|
|
14
|
+
}
|
|
15
|
+
if (typeof value === 'string') {
|
|
16
|
+
const cleaned = value
|
|
17
|
+
.split(',')
|
|
18
|
+
.map((item) => item.trim())
|
|
19
|
+
.filter(Boolean);
|
|
20
|
+
return cleaned.length > 0 ? Array.from(new Set(cleaned)) : undefined;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
6
24
|
function getAgentsPath() {
|
|
7
25
|
let basePath;
|
|
8
26
|
if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
|
|
@@ -47,11 +65,11 @@ app.get('/', async (c) => {
|
|
|
47
65
|
const document = {
|
|
48
66
|
filename,
|
|
49
67
|
metadata: {
|
|
68
|
+
...data,
|
|
50
69
|
name: data.name || title,
|
|
51
70
|
description: data.description || '',
|
|
52
71
|
color: data.color,
|
|
53
|
-
tools: data.tools
|
|
54
|
-
...data
|
|
72
|
+
tools: normalizeTools(data.tools)
|
|
55
73
|
},
|
|
56
74
|
content,
|
|
57
75
|
title
|
|
@@ -98,6 +116,13 @@ app.put('/', async (c) => {
|
|
|
98
116
|
name: body.name !== undefined ? body.name : currentData.name,
|
|
99
117
|
description: body.description !== undefined ? body.description : currentData.description
|
|
100
118
|
};
|
|
119
|
+
const normalizedTools = normalizeTools(body.metadata?.tools ?? updatedMetadata.tools);
|
|
120
|
+
if (normalizedTools) {
|
|
121
|
+
updatedMetadata.tools = normalizedTools;
|
|
122
|
+
}
|
|
123
|
+
else {
|
|
124
|
+
delete updatedMetadata.tools;
|
|
125
|
+
}
|
|
101
126
|
// Handle name change - might need to rename file
|
|
102
127
|
let newFilename = filename;
|
|
103
128
|
let newFilePath = filePath;
|
|
@@ -3,6 +3,24 @@ import { promises as fs } from 'fs';
|
|
|
3
3
|
import path from 'path';
|
|
4
4
|
import matter from 'gray-matter';
|
|
5
5
|
const app = new Hono();
|
|
6
|
+
function normalizeTools(value) {
|
|
7
|
+
if (!value)
|
|
8
|
+
return undefined;
|
|
9
|
+
if (Array.isArray(value)) {
|
|
10
|
+
const cleaned = value
|
|
11
|
+
.map((item) => (typeof item === 'string' ? item.trim() : ''))
|
|
12
|
+
.filter((item) => Boolean(item));
|
|
13
|
+
return cleaned.length > 0 ? Array.from(new Set(cleaned)) : undefined;
|
|
14
|
+
}
|
|
15
|
+
if (typeof value === 'string') {
|
|
16
|
+
const cleaned = value
|
|
17
|
+
.split(',')
|
|
18
|
+
.map((item) => item.trim())
|
|
19
|
+
.filter(Boolean);
|
|
20
|
+
return cleaned.length > 0 ? Array.from(new Set(cleaned)) : undefined;
|
|
21
|
+
}
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
6
24
|
function getAgentsPath() {
|
|
7
25
|
let basePath;
|
|
8
26
|
if (process.env.NODE_ENV === 'development' && process.env.GAIT_DEV_ROOT) {
|
|
@@ -52,11 +70,11 @@ app.get('/', async (c) => {
|
|
|
52
70
|
return {
|
|
53
71
|
filename: file,
|
|
54
72
|
metadata: {
|
|
73
|
+
...data,
|
|
55
74
|
name: data.name || title,
|
|
56
75
|
description: data.description || '',
|
|
57
76
|
color: data.color,
|
|
58
|
-
tools: data.tools
|
|
59
|
-
...data
|
|
77
|
+
tools: normalizeTools(data.tools)
|
|
60
78
|
},
|
|
61
79
|
content,
|
|
62
80
|
title
|
|
@@ -115,13 +133,22 @@ app.post('/', async (c) => {
|
|
|
115
133
|
// File doesn't exist, which is what we want
|
|
116
134
|
}
|
|
117
135
|
// Prepare frontmatter - filter out undefined values
|
|
118
|
-
const
|
|
136
|
+
const normalizedTools = normalizeTools(body.metadata?.tools);
|
|
137
|
+
const frontmatterSource = {
|
|
138
|
+
...body.metadata,
|
|
119
139
|
name: body.name,
|
|
120
|
-
description: body.description
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
140
|
+
description: body.description
|
|
141
|
+
};
|
|
142
|
+
frontmatterSource.color = typeof body.metadata?.color === 'string' && body.metadata.color
|
|
143
|
+
? body.metadata.color
|
|
144
|
+
: 'blue';
|
|
145
|
+
if (normalizedTools) {
|
|
146
|
+
frontmatterSource.tools = normalizedTools;
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
delete frontmatterSource.tools;
|
|
150
|
+
}
|
|
151
|
+
const frontmatter = Object.fromEntries(Object.entries(frontmatterSource).filter(([, value]) => value !== undefined));
|
|
125
152
|
// Create the markdown content with frontmatter
|
|
126
153
|
const fileContent = matter.stringify(body.content || '', frontmatter);
|
|
127
154
|
await fs.writeFile(filePath, fileContent, 'utf-8');
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lovelybunch/api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.61",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/server-with-static.js",
|
|
6
6
|
"exports": {
|
|
@@ -32,9 +32,9 @@
|
|
|
32
32
|
"dependencies": {
|
|
33
33
|
"@hono/node-server": "^1.13.7",
|
|
34
34
|
"@hono/node-ws": "^1.0.6",
|
|
35
|
-
"@lovelybunch/core": "^1.0.
|
|
36
|
-
"@lovelybunch/mcp": "^1.0.
|
|
37
|
-
"@lovelybunch/types": "^1.0.
|
|
35
|
+
"@lovelybunch/core": "^1.0.61",
|
|
36
|
+
"@lovelybunch/mcp": "^1.0.61",
|
|
37
|
+
"@lovelybunch/types": "^1.0.61",
|
|
38
38
|
"arctic": "^1.9.2",
|
|
39
39
|
"bcrypt": "^5.1.1",
|
|
40
40
|
"cookie": "^0.6.0",
|