@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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@11agents/cli",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "description": "11agents local runtime and telemetry CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -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
- resolve({ code: 127, stdout, stderr: error.message })
37
+ settle({ code: 127, stdout, stderr: error.message })
32
38
  })
33
39
  child.on('close', code => {
34
- resolve({ code: code ?? 1, stdout, stderr })
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 handlerModule.handleRuntimeTask(runtimeTask)
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) {