@11agents/cli 0.1.16 → 0.1.18
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 +53 -10
package/package.json
CHANGED
package/src/commands/runtime.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process'
|
|
2
2
|
import { createHash } from 'node:crypto'
|
|
3
|
-
import { readFileSync } from 'node:fs'
|
|
3
|
+
import { appendFileSync, readFileSync } from 'node:fs'
|
|
4
4
|
import { appendFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
|
|
5
5
|
import os from 'node:os'
|
|
6
6
|
import { dirname, resolve } from 'node:path'
|
|
@@ -20,7 +20,7 @@ function sleep(ms) {
|
|
|
20
20
|
return new Promise(resolve => setTimeout(resolve, ms))
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
export function runProcess(command, args, { input = '', cwd = process.cwd(), env = process.env } = {}) {
|
|
23
|
+
export function runProcess(command, args, { input = '', cwd = process.cwd(), env = process.env, onStdoutChunk } = {}) {
|
|
24
24
|
return new Promise(resolve => {
|
|
25
25
|
let settled = false
|
|
26
26
|
const child = spawn(command, args, { cwd, env, stdio: ['pipe', 'pipe', 'pipe'] })
|
|
@@ -31,7 +31,10 @@ export function runProcess(command, args, { input = '', cwd = process.cwd(), env
|
|
|
31
31
|
settled = true
|
|
32
32
|
resolve(result)
|
|
33
33
|
}
|
|
34
|
-
child.stdout.on('data', chunk => {
|
|
34
|
+
child.stdout.on('data', chunk => {
|
|
35
|
+
stdout += chunk
|
|
36
|
+
if (onStdoutChunk) onStdoutChunk(chunk)
|
|
37
|
+
})
|
|
35
38
|
child.stderr.on('data', chunk => { stderr += chunk })
|
|
36
39
|
child.on('error', error => {
|
|
37
40
|
settle({ code: 127, stdout, stderr: error.message })
|
|
@@ -769,7 +772,15 @@ async function materializeSkillsIfChanged({ task, workdir, flags, deps }) {
|
|
|
769
772
|
const statePath = path.join(skillsDir, 'skills-state.json')
|
|
770
773
|
const nextHash = stableHash(skills)
|
|
771
774
|
const current = await readJsonFile(statePath, {})
|
|
772
|
-
if (current.hash === nextHash)
|
|
775
|
+
if (current.hash === nextHash) {
|
|
776
|
+
const allExist = (await Promise.all(
|
|
777
|
+
skills.map(skill =>
|
|
778
|
+
readFile(path.join(skillsDir, slugify(skill.name, 'skill'), 'SKILL.md'), 'utf8')
|
|
779
|
+
.then(() => true).catch(() => false)
|
|
780
|
+
)
|
|
781
|
+
)).every(Boolean)
|
|
782
|
+
if (allExist) return { changed: false, count: skills.length }
|
|
783
|
+
}
|
|
773
784
|
|
|
774
785
|
await mkdir(skillsDir, { recursive: true })
|
|
775
786
|
for (const skill of skills) {
|
|
@@ -883,10 +894,16 @@ function agentEnvironment(task) {
|
|
|
883
894
|
|
|
884
895
|
async function prepareRuntimeTask(task, flags, deps, config) {
|
|
885
896
|
const workdir = flag(flags, 'codex-workdir') || projectDirForTask(task, flags, deps)
|
|
886
|
-
const
|
|
897
|
+
const agentDir = path.join(workdir, 'agents', slugify(agentNameForTask(task), 'agent'))
|
|
898
|
+
const agentSkillsDir = path.join(agentDir, 'skills')
|
|
899
|
+
const agentMemoryDir = path.join(agentDir, 'memory')
|
|
900
|
+
const agentResultsDir = path.join(agentDir, 'results')
|
|
901
|
+
const tmpDir = path.join(agentDir, 'tmp', sanitizeTaskId(task.id))
|
|
887
902
|
const runDir = path.join(workdir, 'runs', sanitizeTaskId(task.id))
|
|
888
903
|
await mkdir(tmpDir, { recursive: true })
|
|
889
904
|
await mkdir(runDir, { recursive: true })
|
|
905
|
+
await mkdir(agentResultsDir, { recursive: true })
|
|
906
|
+
await mkdir(agentMemoryDir, { recursive: true })
|
|
890
907
|
|
|
891
908
|
const database = await syncDatabaseIfNeeded({ task, workdir, config, flags, deps })
|
|
892
909
|
const skills = await materializeSkillsIfChanged({ task, workdir, flags, deps })
|
|
@@ -898,6 +915,10 @@ async function prepareRuntimeTask(task, flags, deps, config) {
|
|
|
898
915
|
...process.env,
|
|
899
916
|
...agentEnvironment(task),
|
|
900
917
|
ELEVENAGENTS_PROJECT_DIR: workdir,
|
|
918
|
+
ELEVENAGENTS_AGENT_DIR: agentDir,
|
|
919
|
+
ELEVENAGENTS_AGENT_SKILLS_DIR: agentSkillsDir,
|
|
920
|
+
ELEVENAGENTS_AGENT_MEMORY_DIR: agentMemoryDir,
|
|
921
|
+
ELEVENAGENTS_AGENT_RESULTS_DIR: agentResultsDir,
|
|
901
922
|
ELEVENAGENTS_TASK_TMP: tmpDir,
|
|
902
923
|
ELEVENAGENTS_TASK_ID: String(task.id || ''),
|
|
903
924
|
...(projectToken ? { GTM_SWARM_TOKEN: projectToken } : {}),
|
|
@@ -905,6 +926,10 @@ async function prepareRuntimeTask(task, flags, deps, config) {
|
|
|
905
926
|
|
|
906
927
|
return {
|
|
907
928
|
workdir,
|
|
929
|
+
agent_dir: agentDir,
|
|
930
|
+
agent_skills_dir: agentSkillsDir,
|
|
931
|
+
agent_memory_dir: agentMemoryDir,
|
|
932
|
+
agent_results_dir: agentResultsDir,
|
|
908
933
|
tmp_dir: tmpDir,
|
|
909
934
|
run_dir: runDir,
|
|
910
935
|
project_slug: projectSlugForTask(task, flags),
|
|
@@ -923,13 +948,23 @@ function buildCodexPrompt(task) {
|
|
|
923
948
|
'Execution workspace:',
|
|
924
949
|
compactJson({
|
|
925
950
|
workdir: task.execution_context?.workdir,
|
|
951
|
+
agent_skills_dir: task.execution_context?.agent_skills_dir,
|
|
952
|
+
agent_memory_dir: task.execution_context?.agent_memory_dir,
|
|
953
|
+
agent_results_dir: task.execution_context?.agent_results_dir,
|
|
926
954
|
tmp_dir: task.execution_context?.tmp_dir,
|
|
927
955
|
project_slug: task.execution_context?.project_slug,
|
|
928
|
-
knowledge_base: './knowledge_base
|
|
929
|
-
rule: 'Treat the project directory as read-only project context except ./knowledge_base/ for durable project knowledge updates and ./tmp/<taskId>/ for temporary scratch files.',
|
|
930
|
-
cleanup: 'Temporary files under ./tmp/<taskId>/ are removed by the CLI after the task finishes.',
|
|
956
|
+
knowledge_base: task.execution_context?.workdir ? path.join(task.execution_context.workdir, 'knowledge_base') : './knowledge_base',
|
|
931
957
|
}),
|
|
932
958
|
'',
|
|
959
|
+
'Directory rules — follow strictly:',
|
|
960
|
+
'1. agent_skills_dir: BEFORE starting work, list files here to see which skills are installed.',
|
|
961
|
+
' Each skill is a subdirectory with a SKILL.md. If a skill you need is present, read its SKILL.md and follow it.',
|
|
962
|
+
'2. agent_results_dir: Write all final deliverables and task outputs here (generated content, reports, files).',
|
|
963
|
+
'3. agent_memory_dir: After completing work, record key decisions, facts, and learned context here.',
|
|
964
|
+
' Append to index.qmd or create new .qmd files. This memory persists across future task runs.',
|
|
965
|
+
'4. tmp_dir: Scratch/working files only. This directory is deleted by the CLI after the task finishes — do NOT put deliverables here.',
|
|
966
|
+
'5. workdir: Treat as read-only project context except for the four agent directories and knowledge_base above.',
|
|
967
|
+
'',
|
|
933
968
|
'Task context:',
|
|
934
969
|
compactJson({
|
|
935
970
|
queue_event: task.queue_event,
|
|
@@ -1012,7 +1047,10 @@ async function runCodex({ task, prompt, flags = {}, deps }) {
|
|
|
1012
1047
|
})
|
|
1013
1048
|
deps.log(JSON.stringify({ running: 'codex exec', command: commandLine, workdir }, null, 2))
|
|
1014
1049
|
const taskEnv = task.execution_context?.env || process.env
|
|
1015
|
-
|
|
1050
|
+
const stdoutLogPath = runDir ? path.join(runDir, 'stdout.log') : ''
|
|
1051
|
+
if (stdoutLogPath) await writeRunFile(runDir, 'stdout.log', '')
|
|
1052
|
+
const onStdoutChunk = stdoutLogPath ? (chunk) => { try { appendFileSync(stdoutLogPath, chunk) } catch {} } : undefined
|
|
1053
|
+
let result = await deps.runProcess(codexBin, args, { input: `/goal ${prompt}`, cwd: workdir, env: taskEnv, onStdoutChunk })
|
|
1016
1054
|
|
|
1017
1055
|
// When --codex-sandbox is set but bwrap is unavailable in the container (missing CAP_NET_ADMIN),
|
|
1018
1056
|
// fall back to --yolo exec which runs commands directly without bwrap.
|
|
@@ -1023,7 +1061,8 @@ async function runCodex({ task, prompt, flags = {}, deps }) {
|
|
|
1023
1061
|
const fallbackLine = [codexBin, ...fallbackArgs].map(v => JSON.stringify(String(v))).join(' ')
|
|
1024
1062
|
deps.log(JSON.stringify({ warning: 'bwrap unavailable in this environment, retrying without sandbox', fallback_command: fallbackLine }))
|
|
1025
1063
|
await updateRunMeta(runDir, { bwrap_fallback: true, fallback_command_line: fallbackLine })
|
|
1026
|
-
|
|
1064
|
+
if (stdoutLogPath) await writeRunFile(runDir, 'stdout.log', '')
|
|
1065
|
+
result = await deps.runProcess(codexBin, fallbackArgs, { input: `/goal ${prompt}`, cwd: workdir, env: taskEnv, onStdoutChunk })
|
|
1027
1066
|
}
|
|
1028
1067
|
}
|
|
1029
1068
|
const rawStdout = String(result.stdout || '')
|
|
@@ -1106,10 +1145,14 @@ async function runClaude({ task, prompt, flags = {}, deps }) {
|
|
|
1106
1145
|
|
|
1107
1146
|
deps.log(JSON.stringify({ running: 'claude --print', command: commandLine, workdir }, null, 2))
|
|
1108
1147
|
|
|
1148
|
+
const stdoutLogPath = runDir ? path.join(runDir, 'stdout.log') : ''
|
|
1149
|
+
if (stdoutLogPath) await writeRunFile(runDir, 'stdout.log', '')
|
|
1150
|
+
const onStdoutChunk = stdoutLogPath ? (chunk) => { try { appendFileSync(stdoutLogPath, chunk) } catch {} } : undefined
|
|
1109
1151
|
const result = await deps.runProcess(claudeBin, args, {
|
|
1110
1152
|
input: prompt,
|
|
1111
1153
|
cwd: workdir,
|
|
1112
1154
|
env: task.execution_context?.env || process.env,
|
|
1155
|
+
onStdoutChunk,
|
|
1113
1156
|
})
|
|
1114
1157
|
|
|
1115
1158
|
const rawStdout = String(result.stdout || '')
|