@11agents/cli 0.1.15 → 0.1.16
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/package.json +1 -1
- package/src/commands/runtime.js +118 -26
- package/src/mcp.js +32 -0
package/package.json
CHANGED
package/src/commands/runtime.js
CHANGED
|
@@ -74,6 +74,7 @@ function runtimeDeps(overrides = {}) {
|
|
|
74
74
|
log: overrides.log || (value => console.log(value)),
|
|
75
75
|
homeDir: overrides.homeDir || os.homedir(),
|
|
76
76
|
runCodex: overrides.runCodex || runCodex,
|
|
77
|
+
runClaude: overrides.runClaude || runClaude,
|
|
77
78
|
runProcess: overrides.runProcess || runProcess,
|
|
78
79
|
requestJson: overrides.requestJson || requestJson,
|
|
79
80
|
sleep: overrides.sleep || sleep,
|
|
@@ -889,12 +890,17 @@ async function prepareRuntimeTask(task, flags, deps, config) {
|
|
|
889
890
|
|
|
890
891
|
const database = await syncDatabaseIfNeeded({ task, workdir, config, flags, deps })
|
|
891
892
|
const skills = await materializeSkillsIfChanged({ task, workdir, flags, deps })
|
|
893
|
+
|
|
894
|
+
// Resolve and inject the project token so MCP subprocesses (e.g. `11agents mcp start`)
|
|
895
|
+
// spawned by the runtime agent can authenticate without needing credentials on disk.
|
|
896
|
+
const projectToken = await projectSyncToken(projectTokenCandidatesForTask(task, flags), flags, deps)
|
|
892
897
|
const env = {
|
|
893
898
|
...process.env,
|
|
894
899
|
...agentEnvironment(task),
|
|
895
900
|
ELEVENAGENTS_PROJECT_DIR: workdir,
|
|
896
901
|
ELEVENAGENTS_TASK_TMP: tmpDir,
|
|
897
902
|
ELEVENAGENTS_TASK_ID: String(task.id || ''),
|
|
903
|
+
...(projectToken ? { GTM_SWARM_TOKEN: projectToken } : {}),
|
|
898
904
|
}
|
|
899
905
|
|
|
900
906
|
return {
|
|
@@ -981,34 +987,20 @@ async function runCodex({ task, prompt, flags = {}, deps }) {
|
|
|
981
987
|
const runDir = task.execution_context?.run_dir
|
|
982
988
|
const lastMessagePath = runDir ? path.join(runDir, 'last_message.md') : ''
|
|
983
989
|
const jsonLogArgs = lastMessagePath ? ['--json', '--output-last-message', lastMessagePath] : ['--json']
|
|
984
|
-
const args = sandbox
|
|
985
|
-
? [
|
|
986
|
-
'--ask-for-approval',
|
|
987
|
-
'never',
|
|
988
|
-
'exec',
|
|
989
|
-
...jsonLogArgs,
|
|
990
|
-
'--skip-git-repo-check',
|
|
991
|
-
'--sandbox',
|
|
992
|
-
sandbox,
|
|
993
|
-
'-C',
|
|
994
|
-
workdir,
|
|
995
|
-
'-',
|
|
996
|
-
]
|
|
997
|
-
: [
|
|
998
|
-
'--yolo',
|
|
999
|
-
'exec',
|
|
1000
|
-
...jsonLogArgs,
|
|
1001
|
-
'--skip-git-repo-check',
|
|
1002
|
-
'-C',
|
|
1003
|
-
workdir,
|
|
1004
|
-
'-',
|
|
1005
|
-
]
|
|
1006
990
|
const model = flag(flags, 'codex-model')
|
|
1007
991
|
const profile = flag(flags, 'codex-profile')
|
|
1008
|
-
const execIndex = args.indexOf('exec')
|
|
1009
|
-
if (model) args.splice(execIndex + 1, 0, '--model', model)
|
|
1010
|
-
if (profile) args.splice(execIndex + 1, 0, '--profile', profile)
|
|
1011
992
|
|
|
993
|
+
function buildCodexArgs(withSandbox) {
|
|
994
|
+
const built = withSandbox
|
|
995
|
+
? ['--ask-for-approval', 'never', 'exec', ...jsonLogArgs, '--skip-git-repo-check', '--sandbox', withSandbox, '-C', workdir, '-']
|
|
996
|
+
: ['--yolo', 'exec', ...jsonLogArgs, '--skip-git-repo-check', '-C', workdir, '-']
|
|
997
|
+
const execIdx = built.indexOf('exec')
|
|
998
|
+
if (model) built.splice(execIdx + 1, 0, '--model', model)
|
|
999
|
+
if (profile) built.splice(execIdx + 1, 0, '--profile', profile)
|
|
1000
|
+
return built
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
const args = buildCodexArgs(sandbox)
|
|
1012
1004
|
const commandLine = [codexBin, ...args].map(value => JSON.stringify(String(value))).join(' ')
|
|
1013
1005
|
await writeRunFile(runDir, 'prompt.md', `/goal ${prompt}`)
|
|
1014
1006
|
await updateRunMeta(runDir, {
|
|
@@ -1019,7 +1011,21 @@ async function runCodex({ task, prompt, flags = {}, deps }) {
|
|
|
1019
1011
|
workdir,
|
|
1020
1012
|
})
|
|
1021
1013
|
deps.log(JSON.stringify({ running: 'codex exec', command: commandLine, workdir }, null, 2))
|
|
1022
|
-
const
|
|
1014
|
+
const taskEnv = task.execution_context?.env || process.env
|
|
1015
|
+
let result = await deps.runProcess(codexBin, args, { input: `/goal ${prompt}`, cwd: workdir, env: taskEnv })
|
|
1016
|
+
|
|
1017
|
+
// When --codex-sandbox is set but bwrap is unavailable in the container (missing CAP_NET_ADMIN),
|
|
1018
|
+
// fall back to --yolo exec which runs commands directly without bwrap.
|
|
1019
|
+
if (result.code !== 0 && sandbox) {
|
|
1020
|
+
const errOutput = String(result.stderr || '') + String(result.stdout || '')
|
|
1021
|
+
if (errOutput.includes('bwrap:') && (errOutput.includes('Operation not permitted') || errOutput.includes('RTM_NEWADDR'))) {
|
|
1022
|
+
const fallbackArgs = buildCodexArgs(null)
|
|
1023
|
+
const fallbackLine = [codexBin, ...fallbackArgs].map(v => JSON.stringify(String(v))).join(' ')
|
|
1024
|
+
deps.log(JSON.stringify({ warning: 'bwrap unavailable in this environment, retrying without sandbox', fallback_command: fallbackLine }))
|
|
1025
|
+
await updateRunMeta(runDir, { bwrap_fallback: true, fallback_command_line: fallbackLine })
|
|
1026
|
+
result = await deps.runProcess(codexBin, fallbackArgs, { input: `/goal ${prompt}`, cwd: workdir, env: taskEnv })
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1023
1029
|
const rawStdout = String(result.stdout || '')
|
|
1024
1030
|
const transcript = codexTranscriptFromJsonl(rawStdout)
|
|
1025
1031
|
const assistantText = codexAssistantTextFromJsonl(rawStdout)
|
|
@@ -1077,10 +1083,96 @@ async function runCodex({ task, prompt, flags = {}, deps }) {
|
|
|
1077
1083
|
}
|
|
1078
1084
|
}
|
|
1079
1085
|
|
|
1086
|
+
async function runClaude({ task, prompt, flags = {}, deps }) {
|
|
1087
|
+
const claudeBin = flag(flags, 'claude-bin', 'claude')
|
|
1088
|
+
const workdir = flag(flags, 'claude-workdir') || flag(flags, 'codex-workdir') || task.execution_context?.workdir || process.cwd()
|
|
1089
|
+
const model = flag(flags, 'claude-model')
|
|
1090
|
+
const runDir = task.execution_context?.run_dir
|
|
1091
|
+
|
|
1092
|
+
// --dangerously-skip-permissions bypasses bwrap sandboxing and auto-approves MCP tool calls,
|
|
1093
|
+
// which are both required for headless remote runtimes running inside containers.
|
|
1094
|
+
const args = ['--dangerously-skip-permissions', '--print']
|
|
1095
|
+
if (model) args.push('--model', model)
|
|
1096
|
+
|
|
1097
|
+
const commandLine = [claudeBin, ...args].map(a => JSON.stringify(String(a))).join(' ')
|
|
1098
|
+
await writeRunFile(runDir, 'prompt.md', prompt)
|
|
1099
|
+
await updateRunMeta(runDir, {
|
|
1100
|
+
provider: 'claude',
|
|
1101
|
+
command: claudeBin,
|
|
1102
|
+
args,
|
|
1103
|
+
command_line: commandLine,
|
|
1104
|
+
workdir,
|
|
1105
|
+
})
|
|
1106
|
+
|
|
1107
|
+
deps.log(JSON.stringify({ running: 'claude --print', command: commandLine, workdir }, null, 2))
|
|
1108
|
+
|
|
1109
|
+
const result = await deps.runProcess(claudeBin, args, {
|
|
1110
|
+
input: prompt,
|
|
1111
|
+
cwd: workdir,
|
|
1112
|
+
env: task.execution_context?.env || process.env,
|
|
1113
|
+
})
|
|
1114
|
+
|
|
1115
|
+
const rawStdout = String(result.stdout || '')
|
|
1116
|
+
const output = rawStdout.trim()
|
|
1117
|
+
const error = String(result.stderr || '').trim()
|
|
1118
|
+
|
|
1119
|
+
await writeRunFile(runDir, 'stdout.log', rawStdout)
|
|
1120
|
+
await writeRunFile(runDir, 'stderr.log', String(result.stderr || ''))
|
|
1121
|
+
await updateRunMeta(runDir, { exit_code: result.code })
|
|
1122
|
+
|
|
1123
|
+
if (result.code !== 0) {
|
|
1124
|
+
return {
|
|
1125
|
+
comment: `${error || output || `claude exited with status ${result.code}`}\n\nClaude command: ${commandLine}`,
|
|
1126
|
+
status: 'failed',
|
|
1127
|
+
}
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
if (knowledgeDeepOrganizeSpec(task)) {
|
|
1131
|
+
const structured = extractJsonObject(output)
|
|
1132
|
+
if (structured?.knowledge_snapshot || structured?.knowledgeSnapshot) {
|
|
1133
|
+
return {
|
|
1134
|
+
...structured,
|
|
1135
|
+
comment: String(structured.comment || structured.summary || output || `Claude completed task ${task.id}.`),
|
|
1136
|
+
memory_delta: String(structured.memory_delta || structured.memoryDelta || `Claude completed task ${task.id}.`),
|
|
1137
|
+
status: structured.status ? String(structured.status) : 'in_review',
|
|
1138
|
+
}
|
|
1139
|
+
}
|
|
1140
|
+
const recoveredSnapshot = buildRecoveredDeepKnowledgeSnapshot(task, [
|
|
1141
|
+
structured?.comment || structured?.summary || '',
|
|
1142
|
+
structured?.memory_delta || structured?.memoryDelta || '',
|
|
1143
|
+
output,
|
|
1144
|
+
].filter(Boolean).join('\n\n'))
|
|
1145
|
+
if (recoveredSnapshot) {
|
|
1146
|
+
return {
|
|
1147
|
+
comment: [
|
|
1148
|
+
String(structured?.comment || structured?.summary || output || `Claude completed task ${task.id}.`).trim(),
|
|
1149
|
+
'Recovered a knowledge_snapshot from the worker output because local tooling or MCP push was unavailable.',
|
|
1150
|
+
].filter(Boolean).join('\n\n'),
|
|
1151
|
+
memory_delta: [
|
|
1152
|
+
String(structured?.memory_delta || structured?.memoryDelta || '').trim(),
|
|
1153
|
+
'Recovered deep knowledge organization snapshot from worker output.',
|
|
1154
|
+
].filter(Boolean).join('\n'),
|
|
1155
|
+
status: 'in_review',
|
|
1156
|
+
knowledge_snapshot: recoveredSnapshot,
|
|
1157
|
+
}
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
|
|
1161
|
+
return {
|
|
1162
|
+
comment: output || `Claude completed task ${task.id}.`,
|
|
1163
|
+
memory_delta: `Claude completed task ${task.id}.`,
|
|
1164
|
+
status: 'in_review',
|
|
1165
|
+
}
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1080
1168
|
function defaultTaskHandler(flags, deps) {
|
|
1081
1169
|
return {
|
|
1082
1170
|
async handleRuntimeTask(task) {
|
|
1083
1171
|
const provider = task.runtime?.provider || ''
|
|
1172
|
+
if (provider === 'claude') {
|
|
1173
|
+
const prompt = buildCodexPrompt(task)
|
|
1174
|
+
return deps.runClaude({ task, prompt, flags, deps })
|
|
1175
|
+
}
|
|
1084
1176
|
if (provider !== 'codex') {
|
|
1085
1177
|
return {
|
|
1086
1178
|
comment: `unsupported runtime provider: ${provider || 'unknown'}`,
|
package/src/mcp.js
CHANGED
|
@@ -17,6 +17,22 @@ const TOOLS = [
|
|
|
17
17
|
},
|
|
18
18
|
},
|
|
19
19
|
},
|
|
20
|
+
{
|
|
21
|
+
name: 'database_sync',
|
|
22
|
+
description: 'Pull or push the cloud project database snapshot with a project token.',
|
|
23
|
+
inputSchema: {
|
|
24
|
+
type: 'object',
|
|
25
|
+
required: ['project', 'mode'],
|
|
26
|
+
properties: {
|
|
27
|
+
project: { type: 'string' },
|
|
28
|
+
mode: { type: 'string', enum: ['pull', 'push'] },
|
|
29
|
+
token: { type: 'string' },
|
|
30
|
+
server: { type: 'string' },
|
|
31
|
+
snapshot: { type: 'object' },
|
|
32
|
+
metadata: { type: 'object' },
|
|
33
|
+
},
|
|
34
|
+
},
|
|
35
|
+
},
|
|
20
36
|
]
|
|
21
37
|
|
|
22
38
|
function textResult(value) {
|
|
@@ -64,6 +80,22 @@ export async function handleMcpRequest(request, deps = {}) {
|
|
|
64
80
|
})
|
|
65
81
|
return textResult(result)
|
|
66
82
|
}
|
|
83
|
+
if (name === 'database_sync') {
|
|
84
|
+
const token = await resolveProjectToken(args.project, {
|
|
85
|
+
homeDir: deps.homeDir,
|
|
86
|
+
token: args.token,
|
|
87
|
+
})
|
|
88
|
+
const server = args.server || 'https://app.11agents.ai'
|
|
89
|
+
const result = await (deps.requestJson || requestJson)(
|
|
90
|
+
`/api/projects/${encodeURIComponent(args.project)}/database/sync`,
|
|
91
|
+
{
|
|
92
|
+
method: 'POST',
|
|
93
|
+
body: { mode: args.mode || 'pull', snapshot: args.snapshot, metadata: args.metadata },
|
|
94
|
+
config: { token, server },
|
|
95
|
+
}
|
|
96
|
+
)
|
|
97
|
+
return textResult(result)
|
|
98
|
+
}
|
|
67
99
|
throw new Error(`unknown MCP tool: ${name}`)
|
|
68
100
|
}
|
|
69
101
|
|