@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@11agents/cli",
3
- "version": "0.1.15",
3
+ "version": "0.1.16",
4
4
  "description": "11agents local runtime and telemetry CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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 result = await deps.runProcess(codexBin, args, { input: `/goal ${prompt}`, cwd: workdir, env: task.execution_context?.env || process.env })
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