@11agents/cli 0.1.19 → 0.1.20

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.19",
3
+ "version": "0.1.20",
4
4
  "description": "11agents local runtime and telemetry CLI",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,7 +1,7 @@
1
1
  import { spawn } from 'node:child_process'
2
2
  import { createHash } from 'node:crypto'
3
3
  import { appendFileSync, readFileSync } from 'node:fs'
4
- import { appendFile, mkdir, readFile, rm, writeFile } from 'node:fs/promises'
4
+ import { appendFile, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises'
5
5
  import os from 'node:os'
6
6
  import { dirname, resolve } from 'node:path'
7
7
  import path from 'node:path'
@@ -86,27 +86,49 @@ function runtimeDeps(overrides = {}) {
86
86
  }
87
87
  }
88
88
 
89
- function currentClaimPath(homeDir) {
89
+ function legacyClaimPath(homeDir) {
90
90
  return path.join(homeDir, '.11agents', 'claim_id')
91
91
  }
92
92
 
93
+ function claimsDirPath(homeDir) {
94
+ return path.join(homeDir, '.11agents', 'claims')
95
+ }
96
+
97
+ function claimFilePath(homeDir, taskId) {
98
+ return path.join(claimsDirPath(homeDir), `${sanitizeTaskId(taskId)}.json`)
99
+ }
100
+
93
101
  async function writeCurrentClaim(deps, task, machineKey) {
94
102
  const payload = {
95
103
  task_id: String(task.id || ''),
96
104
  runtime_id: String(task.runtime_id || task.runtime?.id || ''),
97
105
  machine_key: String(task.runtime?.machine_key || machineKey || ''),
98
106
  }
99
- await mkdir(path.dirname(currentClaimPath(deps.homeDir)), { recursive: true })
100
- await writeFile(currentClaimPath(deps.homeDir), JSON.stringify(payload))
107
+ await mkdir(claimsDirPath(deps.homeDir), { recursive: true })
108
+ await writeFile(claimFilePath(deps.homeDir, task.id), JSON.stringify(payload))
101
109
  return payload
102
110
  }
103
111
 
104
- async function readCurrentClaim(deps) {
105
- return readJsonFile(currentClaimPath(deps.homeDir), null)
112
+ async function clearCurrentClaim(deps, taskId) {
113
+ await rm(claimFilePath(deps.homeDir, taskId), { force: true })
106
114
  }
107
115
 
108
- async function clearCurrentClaim(deps) {
109
- await rm(currentClaimPath(deps.homeDir), { force: true })
116
+ async function readAllCurrentClaims(deps) {
117
+ const claims = []
118
+ // Backward compat: consume legacy single-claim file
119
+ const legacy = await readJsonFile(legacyClaimPath(deps.homeDir), null)
120
+ if (legacy?.task_id && legacy?.runtime_id) {
121
+ claims.push({ ...legacy, _path: legacyClaimPath(deps.homeDir) })
122
+ }
123
+ // Per-task claim files
124
+ const entries = await readdir(claimsDirPath(deps.homeDir)).catch(err => (err?.code === 'ENOENT' ? [] : Promise.reject(err)))
125
+ for (const entry of entries) {
126
+ if (!entry.endsWith('.json')) continue
127
+ const filePath = path.join(claimsDirPath(deps.homeDir), entry)
128
+ const claim = await readJsonFile(filePath, null)
129
+ if (claim?.task_id && claim?.runtime_id) claims.push({ ...claim, _path: filePath })
130
+ }
131
+ return claims
110
132
  }
111
133
 
112
134
  function errorMessage(error) {
@@ -339,15 +361,20 @@ function codexAssistantTextFromJsonl(text) {
339
361
  return messages.join('\n\n')
340
362
  }
341
363
 
342
- async function failPersistedCurrentClaim(flags, deps, comment) {
343
- const claim = await readCurrentClaim(deps)
344
- if (!claim?.task_id || !claim?.runtime_id) return false
345
- await deps.requestJson('/api/runtime/tasks/complete', {
346
- method: 'POST',
347
- body: failedClaimCompletionBody(claim, comment),
348
- config: configFromFlags(flags),
349
- })
350
- await clearCurrentClaim(deps)
364
+ async function failAllPersistedClaims(flags, deps, comment) {
365
+ const claims = await readAllCurrentClaims(deps)
366
+ if (!claims.length) return false
367
+ const config = configFromFlags(flags)
368
+ for (const claim of claims) {
369
+ try {
370
+ await deps.requestJson('/api/runtime/tasks/complete', {
371
+ method: 'POST',
372
+ body: failedClaimCompletionBody(claim, comment),
373
+ config,
374
+ })
375
+ } catch {}
376
+ await rm(claim._path, { force: true })
377
+ }
351
378
  return true
352
379
  }
353
380
 
@@ -357,14 +384,14 @@ function installCurrentClaimExitHandlers(flags, deps) {
357
384
  if (shuttingDown) return
358
385
  shuttingDown = true
359
386
  try {
360
- await failPersistedCurrentClaim(
387
+ await failAllPersistedClaims(
361
388
  flags,
362
389
  deps,
363
390
  `Runtime task failed locally: daemon received ${signal} before the claimed task completed.`
364
391
  )
365
392
  } catch (error) {
366
393
  deps.log(JSON.stringify({
367
- warning: 'failed to mark current claimed task failed during daemon shutdown',
394
+ warning: 'failed to mark current claimed tasks failed during daemon shutdown',
368
395
  signal,
369
396
  error: errorMessage(error),
370
397
  }, null, 2))
@@ -1365,7 +1392,7 @@ async function runOneRuntimeTaskSlot(runtime, config, machineKey, registration,
1365
1392
  config,
1366
1393
  })
1367
1394
  ), deps, retryState)
1368
- await clearCurrentClaim(deps)
1395
+ await clearCurrentClaim(deps, runtimeTask.id)
1369
1396
  deps.log(JSON.stringify(result, null, 2))
1370
1397
  return true
1371
1398
  }
@@ -1412,7 +1439,7 @@ export async function startRuntimeDaemon(flags = {}, deps = {}) {
1412
1439
  const uninstallExitHandlers = installCurrentClaimExitHandlers(flags, resolvedDeps)
1413
1440
  try {
1414
1441
  let registration = await runWithDaemonRetry('register runtime', () => registerRuntime(flags, resolvedDeps), resolvedDeps, retryState)
1415
- await runWithDaemonRetry('recover current claimed task', () => failPersistedCurrentClaim(
1442
+ await runWithDaemonRetry('recover current claimed task', () => failAllPersistedClaims(
1416
1443
  flags,
1417
1444
  resolvedDeps,
1418
1445
  'Runtime task failed locally: daemon restarted with a persisted claimed task that had not completed.'
@@ -1447,7 +1474,7 @@ export async function startRuntimeDaemon(flags = {}, deps = {}) {
1447
1474
  }
1448
1475
  } catch (error) {
1449
1476
  try {
1450
- await failPersistedCurrentClaim(
1477
+ await failAllPersistedClaims(
1451
1478
  flags,
1452
1479
  resolvedDeps,
1453
1480
  `Runtime task failed locally: daemon exited with error before the claimed task completed: ${errorMessage(error)}`