@11agents/cli 0.1.11 → 0.1.13
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 +58 -9
package/package.json
CHANGED
package/src/commands/runtime.js
CHANGED
|
@@ -20,18 +20,28 @@ function sleep(ms) {
|
|
|
20
20
|
return new Promise(resolve => setTimeout(resolve, ms))
|
|
21
21
|
}
|
|
22
22
|
|
|
23
|
-
function runProcess(command, args, { input = '', cwd = process.cwd(), env = process.env } = {}) {
|
|
23
|
+
export function runProcess(command, args, { input = '', cwd = process.cwd(), env = process.env } = {}) {
|
|
24
24
|
return new Promise(resolve => {
|
|
25
|
+
let settled = false
|
|
25
26
|
const child = spawn(command, args, { cwd, env, stdio: ['pipe', 'pipe', 'pipe'] })
|
|
26
27
|
let stdout = ''
|
|
27
28
|
let stderr = ''
|
|
29
|
+
const settle = result => {
|
|
30
|
+
if (settled) return
|
|
31
|
+
settled = true
|
|
32
|
+
resolve(result)
|
|
33
|
+
}
|
|
28
34
|
child.stdout.on('data', chunk => { stdout += chunk })
|
|
29
35
|
child.stderr.on('data', chunk => { stderr += chunk })
|
|
30
36
|
child.on('error', error => {
|
|
31
|
-
|
|
37
|
+
settle({ code: 127, stdout, stderr: error.message })
|
|
32
38
|
})
|
|
33
39
|
child.on('close', code => {
|
|
34
|
-
|
|
40
|
+
settle({ code: code ?? 1, stdout, stderr })
|
|
41
|
+
})
|
|
42
|
+
child.stdin.on('error', error => {
|
|
43
|
+
if (error?.code === 'EPIPE' || error?.code === 'ERR_STREAM_DESTROYED') return
|
|
44
|
+
stderr = stderr ? `${stderr}\n${error.message}` : error.message
|
|
35
45
|
})
|
|
36
46
|
child.stdin.end(input)
|
|
37
47
|
})
|
|
@@ -86,6 +96,41 @@ function createRetryState() {
|
|
|
86
96
|
return { failures: 0 }
|
|
87
97
|
}
|
|
88
98
|
|
|
99
|
+
async function heartbeatRegisteredRuntime(registration, flags, deps) {
|
|
100
|
+
const config = configFromFlags(flags)
|
|
101
|
+
const machineKey = registration?.machine?.machine_key || machineOverride(flags) || ''
|
|
102
|
+
if (!machineKey) return null
|
|
103
|
+
return deps.requestJson('/api/runtime/machines/heartbeat', {
|
|
104
|
+
method: 'POST',
|
|
105
|
+
body: {
|
|
106
|
+
machine_key: machineKey,
|
|
107
|
+
runtime_providers: (registration?.runtimes || []).map(runtime => runtime.provider).filter(Boolean),
|
|
108
|
+
health: {
|
|
109
|
+
heartbeat_at: new Date().toISOString(),
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
config,
|
|
113
|
+
})
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async function runWithRuntimeHeartbeat(operation, registration, flags, deps, heartbeatIntervalMs) {
|
|
117
|
+
const intervalMs = Math.max(10, Math.min(Number(heartbeatIntervalMs) || 15000, 60000))
|
|
118
|
+
const timer = setInterval(() => {
|
|
119
|
+
heartbeatRegisteredRuntime(registration, flags, deps).catch(error => {
|
|
120
|
+
deps.log(JSON.stringify({
|
|
121
|
+
warning: 'runtime heartbeat during task failed',
|
|
122
|
+
error: errorMessage(error),
|
|
123
|
+
}, null, 2))
|
|
124
|
+
})
|
|
125
|
+
}, intervalMs)
|
|
126
|
+
timer.unref?.()
|
|
127
|
+
try {
|
|
128
|
+
return await operation()
|
|
129
|
+
} finally {
|
|
130
|
+
clearInterval(timer)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
89
134
|
async function runWithDaemonRetry(label, operation, deps, retryState) {
|
|
90
135
|
while (true) {
|
|
91
136
|
try {
|
|
@@ -815,8 +860,6 @@ async function runCodex({ task, prompt, flags = {}, deps }) {
|
|
|
815
860
|
'-',
|
|
816
861
|
]
|
|
817
862
|
: [
|
|
818
|
-
'--ask-for-approval',
|
|
819
|
-
'never',
|
|
820
863
|
'--yolo',
|
|
821
864
|
'exec',
|
|
822
865
|
'--skip-git-repo-check',
|
|
@@ -898,7 +941,7 @@ function defaultTaskHandler(flags, deps) {
|
|
|
898
941
|
}
|
|
899
942
|
}
|
|
900
943
|
|
|
901
|
-
async function claimAndRunRuntimeTasks(registration, flags, deps, handlerModule, retryState = createRetryState()) {
|
|
944
|
+
async function claimAndRunRuntimeTasks(registration, flags, deps, handlerModule, retryState = createRetryState(), heartbeatIntervalMs = 15000) {
|
|
902
945
|
if (!handlerModule) return 0
|
|
903
946
|
const config = configFromFlags(flags)
|
|
904
947
|
const machineKey = registration?.machine?.machine_key || machineOverride(flags) || ''
|
|
@@ -960,7 +1003,13 @@ async function claimAndRunRuntimeTasks(registration, flags, deps, handlerModule,
|
|
|
960
1003
|
executionContext = await prepareRuntimeTask(runtimeTask, flags, deps, config)
|
|
961
1004
|
runtimeTask.execution_context = executionContext
|
|
962
1005
|
try {
|
|
963
|
-
completion = await
|
|
1006
|
+
completion = await runWithRuntimeHeartbeat(
|
|
1007
|
+
() => handlerModule.handleRuntimeTask(runtimeTask),
|
|
1008
|
+
registration,
|
|
1009
|
+
flags,
|
|
1010
|
+
deps,
|
|
1011
|
+
heartbeatIntervalMs
|
|
1012
|
+
)
|
|
964
1013
|
} catch (error) {
|
|
965
1014
|
completion = {
|
|
966
1015
|
comment: error instanceof Error ? error.message : String(error),
|
|
@@ -1055,7 +1104,7 @@ export async function startRuntimeDaemon(flags = {}, deps = {}) {
|
|
|
1055
1104
|
const retryState = createRetryState()
|
|
1056
1105
|
let registration = await runWithDaemonRetry('register runtime', () => registerRuntime(flags, resolvedDeps), resolvedDeps, retryState)
|
|
1057
1106
|
await syncRuntimeProjectMetadataBestEffort(flags, resolvedDeps)
|
|
1058
|
-
await claimAndRunRuntimeTasks(registration, flags, resolvedDeps, handlerModule, retryState)
|
|
1107
|
+
await claimAndRunRuntimeTasks(registration, flags, resolvedDeps, handlerModule, retryState, heartbeatIntervalMs)
|
|
1059
1108
|
if (once) return
|
|
1060
1109
|
|
|
1061
1110
|
let lastScan = Date.now()
|
|
@@ -1074,7 +1123,7 @@ export async function startRuntimeDaemon(flags = {}, deps = {}) {
|
|
|
1074
1123
|
lastHeartbeat = now
|
|
1075
1124
|
}
|
|
1076
1125
|
if (now - lastTaskPoll >= taskIntervalMs) {
|
|
1077
|
-
await claimAndRunRuntimeTasks(registration, flags, resolvedDeps, handlerModule, retryState)
|
|
1126
|
+
await claimAndRunRuntimeTasks(registration, flags, resolvedDeps, handlerModule, retryState, heartbeatIntervalMs)
|
|
1078
1127
|
lastTaskPoll = now
|
|
1079
1128
|
}
|
|
1080
1129
|
if (now - lastProjectRefresh >= projectRefreshIntervalMs) {
|