@ai-development-environment/control-agent 0.0.129 → 0.0.131

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.
Files changed (2) hide show
  1. package/dist/control-agent.js +232 -66
  2. package/package.json +1 -1
@@ -2288,7 +2288,7 @@ var require_websocket = __commonJS({
2288
2288
  var http = __require("http");
2289
2289
  var net = __require("net");
2290
2290
  var tls = __require("tls");
2291
- var { randomBytes, createHash: createHash8 } = __require("crypto");
2291
+ var { randomBytes, createHash: createHash9 } = __require("crypto");
2292
2292
  var { Duplex, Readable: Readable2 } = __require("stream");
2293
2293
  var { URL: URL2 } = __require("url");
2294
2294
  var PerMessageDeflate2 = require_permessage_deflate();
@@ -2969,7 +2969,7 @@ var require_websocket = __commonJS({
2969
2969
  abortHandshake(websocket, socket, "Invalid Upgrade header");
2970
2970
  return;
2971
2971
  }
2972
- const digest = createHash8("sha1").update(key + GUID).digest("base64");
2972
+ const digest = createHash9("sha1").update(key + GUID).digest("base64");
2973
2973
  if (res.headers["sec-websocket-accept"] !== digest) {
2974
2974
  abortHandshake(websocket, socket, "Invalid Sec-WebSocket-Accept header");
2975
2975
  return;
@@ -3338,7 +3338,7 @@ var require_websocket_server = __commonJS({
3338
3338
  var EventEmitter = __require("events");
3339
3339
  var http = __require("http");
3340
3340
  var { Duplex } = __require("stream");
3341
- var { createHash: createHash8 } = __require("crypto");
3341
+ var { createHash: createHash9 } = __require("crypto");
3342
3342
  var extension2 = require_extension();
3343
3343
  var PerMessageDeflate2 = require_permessage_deflate();
3344
3344
  var subprotocol2 = require_subprotocol();
@@ -3645,7 +3645,7 @@ var require_websocket_server = __commonJS({
3645
3645
  );
3646
3646
  }
3647
3647
  if (this._state > RUNNING) return abortHandshake(socket, 503);
3648
- const digest = createHash8("sha1").update(key + GUID).digest("base64");
3648
+ const digest = createHash9("sha1").update(key + GUID).digest("base64");
3649
3649
  const headers = [
3650
3650
  "HTTP/1.1 101 Switching Protocols",
3651
3651
  "Upgrade: websocket",
@@ -6438,6 +6438,42 @@ var import_websocket = __toESM(require_websocket(), 1);
6438
6438
  var import_websocket_server = __toESM(require_websocket_server(), 1);
6439
6439
  var wrapper_default = import_websocket.default;
6440
6440
 
6441
+ // src/request-errors.ts
6442
+ var MAX_AGENT_REQUEST_ATTEMPTS = 5;
6443
+ var AgentRequestError = class extends Error {
6444
+ retryable;
6445
+ constructor(message2, status2, codes = []) {
6446
+ super(message2);
6447
+ this.name = "AgentRequestError";
6448
+ this.retryable = (status2 < 400 || status2 >= 500 || [408, 425, 429].includes(status2)) && !codes.some(
6449
+ (code) => [
6450
+ "UNAUTHENTICATED",
6451
+ "FORBIDDEN",
6452
+ "BAD_USER_INPUT",
6453
+ "GRAPHQL_VALIDATION_FAILED",
6454
+ "NOT_FOUND"
6455
+ ].includes(code)
6456
+ ) && !/^(?:Job|Run|Run attempt|Run command) not found(?: for this agent)?$/.test(
6457
+ message2
6458
+ );
6459
+ }
6460
+ };
6461
+ function isRetryableAgentError(error) {
6462
+ return !(error instanceof AgentRequestError) || error.retryable;
6463
+ }
6464
+ function waitForAgentRetry(delay3, signal2) {
6465
+ return new Promise((resolve11) => {
6466
+ const finish = () => {
6467
+ clearTimeout(timer);
6468
+ signal2.removeEventListener("abort", finish);
6469
+ resolve11();
6470
+ };
6471
+ const timer = setTimeout(finish, delay3);
6472
+ if (signal2.aborted) finish();
6473
+ else signal2.addEventListener("abort", finish, { once: true });
6474
+ });
6475
+ }
6476
+
6441
6477
  // src/graphql-client.ts
6442
6478
  async function writeArtifactTransferBytes(writer, bytes, position) {
6443
6479
  let written = 0;
@@ -6532,8 +6568,9 @@ var AgentGraphQLClient = class {
6532
6568
  }
6533
6569
  if (!response.ok || typeof body?.mode !== "string") {
6534
6570
  const detail = `HTTP ${response.status} ${response.statusText}`.trim();
6535
- throw new Error(
6536
- !body && raw ? `${detail}: ${raw.slice(0, 500)}` : detail
6571
+ throw new AgentRequestError(
6572
+ !body && raw ? `${detail}: ${raw.slice(0, 500)}` : detail,
6573
+ response.status
6537
6574
  );
6538
6575
  }
6539
6576
  return { mode: body.mode };
@@ -6557,8 +6594,12 @@ var AgentGraphQLClient = class {
6557
6594
  }
6558
6595
  if (!response.ok || body?.errors?.length || !body?.data) {
6559
6596
  const detail = body?.errors?.map((error) => error.message).join("; ") || `HTTP ${response.status} ${response.statusText}`.trim();
6560
- throw new Error(
6561
- !body && raw ? `${detail}: ${raw.slice(0, 500)}` : detail
6597
+ throw new AgentRequestError(
6598
+ !body && raw ? `${detail}: ${raw.slice(0, 500)}` : detail,
6599
+ response.status,
6600
+ body?.errors?.flatMap(
6601
+ ({ extensions }) => extensions?.code ? [extensions.code] : []
6602
+ )
6562
6603
  );
6563
6604
  }
6564
6605
  return body.data;
@@ -11105,7 +11146,7 @@ function tailscaleServeRemovePayload(value) {
11105
11146
  // package.json
11106
11147
  var package_default = {
11107
11148
  name: "@ai-development-environment/control-agent",
11108
- version: "0.0.129",
11149
+ version: "0.0.131",
11109
11150
  description: "Control agent for the AI Development Environment",
11110
11151
  license: "MIT",
11111
11152
  repository: {
@@ -53986,6 +54027,7 @@ var JobExecutor = class {
53986
54027
  repositoryCoordinator;
53987
54028
  running = /* @__PURE__ */ new Map();
53988
54029
  stopping = false;
54030
+ shutdown = new AbortController();
53989
54031
  execute(job) {
53990
54032
  if (this.stopping || this.running.has(job.id)) return;
53991
54033
  const controller = new AbortController();
@@ -54001,6 +54043,7 @@ var JobExecutor = class {
54001
54043
  }
54002
54044
  async cancelAll() {
54003
54045
  this.stopping = true;
54046
+ this.shutdown.abort();
54004
54047
  closeAllWorktreeWatches();
54005
54048
  const jobs = [...this.running.values()];
54006
54049
  for (const { controller } of jobs) controller.abort();
@@ -54059,8 +54102,7 @@ var JobExecutor = class {
54059
54102
  status2 = controller.signal.aborted ? "CANCELLED" : "FAILED";
54060
54103
  console.error(`Job ${claimed.id} failed:`, completionError);
54061
54104
  }
54062
- let retry = 0;
54063
- while (true) {
54105
+ for (let attempt = 1; ; attempt++) {
54064
54106
  try {
54065
54107
  await this.client.completeJob(
54066
54108
  claimed.id,
@@ -54070,13 +54112,21 @@ var JobExecutor = class {
54070
54112
  );
54071
54113
  return;
54072
54114
  } catch (error) {
54115
+ if (this.stopping) return;
54116
+ if (!isRetryableAgentError(error)) {
54117
+ console.error(
54118
+ `Could not report completion for ${claimed.id}; giving up after ${attempt} attempts:`,
54119
+ error instanceof Error ? error.message : error
54120
+ );
54121
+ return;
54122
+ }
54073
54123
  console.error(
54074
54124
  `Could not report completion for ${claimed.id}; retrying:`,
54075
54125
  error instanceof Error ? error.message : error
54076
54126
  );
54127
+ const delay3 = Math.min(3e4, 1e3 * 2 ** Math.min(attempt - 1, 5));
54128
+ await waitForAgentRetry(delay3, this.shutdown.signal);
54077
54129
  if (this.stopping) return;
54078
- const delay3 = Math.min(3e4, 1e3 * 2 ** Math.min(retry++, 5));
54079
- await new Promise((resolve11) => setTimeout(resolve11, delay3));
54080
54130
  }
54081
54131
  }
54082
54132
  }
@@ -54232,18 +54282,22 @@ var CodebaseMonitor = class {
54232
54282
 
54233
54283
  // src/runs/run-manager.ts
54234
54284
  import { execFile as execFile5 } from "node:child_process";
54285
+ import { createHash as createHash8 } from "node:crypto";
54235
54286
  import { mkdir as mkdir10, rm as rm20 } from "node:fs/promises";
54236
54287
  import { dirname as dirname13, join as join23 } from "node:path";
54237
54288
  import { promisify as promisify5 } from "node:util";
54238
54289
 
54239
54290
  // src/runs/journal.ts
54240
54291
  import { randomUUID as randomUUID7 } from "node:crypto";
54292
+ import { createReadStream as createReadStream6 } from "node:fs";
54241
54293
  import {
54242
54294
  appendFile,
54243
54295
  mkdir as mkdir9,
54244
54296
  readFile as readFile12,
54245
54297
  rename as rename7,
54246
54298
  rm as rm19,
54299
+ stat as stat12,
54300
+ truncate,
54247
54301
  writeFile as writeFile11
54248
54302
  } from "node:fs/promises";
54249
54303
  import { dirname as dirname12, join as join22 } from "node:path";
@@ -54256,6 +54310,7 @@ var RunJournal = class {
54256
54310
  attemptId;
54257
54311
  nextSequence = 0;
54258
54312
  acknowledged = -1;
54313
+ acknowledgedOffset = 0;
54259
54314
  loaded = false;
54260
54315
  loading;
54261
54316
  appending = Promise.resolve();
@@ -54288,14 +54343,33 @@ var RunJournal = class {
54288
54343
  const state = JSON.parse(await readFile12(this.statePath, "utf8"));
54289
54344
  this.acknowledged = state.acknowledged ?? -1;
54290
54345
  this.nextSequence = state.nextSequence ?? 0;
54291
- } catch {
54292
- try {
54293
- const events = await this.readEvents();
54294
- this.nextSequence = (events.at(-1)?.sequence ?? -1) + 1;
54295
- } catch {
54296
- this.nextSequence = 0;
54346
+ this.acknowledgedOffset = state.acknowledgedOffset ?? 0;
54347
+ } catch (error) {
54348
+ if (!(error instanceof SyntaxError) && error.code !== "ENOENT")
54349
+ throw error;
54350
+ }
54351
+ const size = await stat12(this.eventsPath).then(
54352
+ ({ size: size2 }) => size2,
54353
+ (error) => {
54354
+ if (error.code === "ENOENT") return 0;
54355
+ throw error;
54297
54356
  }
54357
+ );
54358
+ if (!Number.isSafeInteger(this.acknowledgedOffset) || this.acknowledgedOffset < 0 || this.acknowledgedOffset > size)
54359
+ this.acknowledgedOffset = 0;
54360
+ this.nextSequence = Math.max(this.nextSequence, this.acknowledged + 1);
54361
+ let completeOffset = this.acknowledgedOffset;
54362
+ for await (const { event, endOffset } of this.readEvents(completeOffset)) {
54363
+ this.nextSequence = Math.max(this.nextSequence, event.sequence + 1);
54364
+ if (event.sequence <= this.acknowledged) {
54365
+ this.acknowledgedOffset = endOffset;
54366
+ }
54367
+ completeOffset = endOffset;
54368
+ }
54369
+ if (size > completeOffset) {
54370
+ await truncate(this.eventsPath, completeOffset);
54298
54371
  }
54372
+ await this.saveState();
54299
54373
  this.loaded = true;
54300
54374
  }
54301
54375
  async append(event) {
@@ -54326,27 +54400,28 @@ var RunJournal = class {
54326
54400
  return this.nextSequence - 1;
54327
54401
  }
54328
54402
  async flush(client) {
54329
- await this.load();
54330
- if (this.flushing) return this.flushing;
54331
- this.flushing = this.flushInternal(client).finally(() => {
54332
- this.flushing = void 0;
54333
- });
54334
- return this.flushing;
54403
+ const previous = this.flushing;
54404
+ const operation = (async () => {
54405
+ await previous?.catch(() => void 0);
54406
+ await this.load();
54407
+ await this.appending;
54408
+ await this.flushInternal(client);
54409
+ })();
54410
+ this.flushing = operation;
54411
+ try {
54412
+ await operation;
54413
+ } finally {
54414
+ if (this.flushing === operation) this.flushing = void 0;
54415
+ }
54335
54416
  }
54336
54417
  async flushInternal(client) {
54337
- const pending = (await this.readEvents()).filter(
54338
- ({ sequence }) => sequence > this.acknowledged
54339
- );
54340
- for (let index = 0; index < pending.length; ) {
54341
- const attemptId = pending[index].attemptId ?? this.attemptId;
54342
- let end = index + 1;
54343
- while (end < pending.length && end - index < 100 && (pending[end].attemptId ?? this.attemptId) === attemptId) {
54344
- end += 1;
54345
- }
54346
- const chunk = pending.slice(index, end);
54418
+ let chunk = [];
54419
+ let endOffset = this.acknowledgedOffset;
54420
+ const upload = async () => {
54421
+ if (!chunk.length) return;
54347
54422
  await client.appendRunEvents(
54348
54423
  this.runId,
54349
- attemptId,
54424
+ chunk[0].attemptId ?? this.attemptId,
54350
54425
  chunk.map((value) => {
54351
54426
  const event = { ...value };
54352
54427
  Reflect.deleteProperty(event, "attemptId");
@@ -54354,20 +54429,49 @@ var RunJournal = class {
54354
54429
  })
54355
54430
  );
54356
54431
  this.acknowledged = chunk.at(-1).sequence;
54432
+ this.acknowledgedOffset = endOffset;
54357
54433
  await this.saveState();
54358
- index = end;
54359
- }
54360
- }
54361
- async readEvents() {
54434
+ chunk = [];
54435
+ };
54436
+ for await (const entry of this.readEvents(this.acknowledgedOffset)) {
54437
+ if (chunk.length && (chunk.length === 100 || (chunk[0].attemptId ?? this.attemptId) !== (entry.event.attemptId ?? this.attemptId)))
54438
+ await upload();
54439
+ chunk.push(entry.event);
54440
+ endOffset = entry.endOffset;
54441
+ }
54442
+ await upload();
54443
+ }
54444
+ async *readEvents(start) {
54445
+ const stream = createReadStream6(this.eventsPath, { start });
54446
+ let pending = Buffer.alloc(0);
54447
+ let offset = start;
54362
54448
  try {
54363
- return (await readFile12(this.eventsPath, "utf8")).split("\n").filter(Boolean).map((line) => JSON.parse(line));
54449
+ for await (const bytes of stream) {
54450
+ const buffer = Buffer.concat([pending, bytes]);
54451
+ let index = 0;
54452
+ let newline;
54453
+ while ((newline = buffer.indexOf(10, index)) !== -1) {
54454
+ const line = buffer.subarray(index, newline);
54455
+ offset += newline - index + 1;
54456
+ index = newline + 1;
54457
+ if (line.length) {
54458
+ yield {
54459
+ event: JSON.parse(line.toString("utf8")),
54460
+ endOffset: offset
54461
+ };
54462
+ }
54463
+ }
54464
+ pending = buffer.subarray(index);
54465
+ }
54364
54466
  } catch (error) {
54365
- if (error.code === "ENOENT") return [];
54467
+ if (error.code === "ENOENT") return;
54366
54468
  throw error;
54469
+ } finally {
54470
+ stream.destroy();
54367
54471
  }
54368
54472
  }
54369
54473
  saveState() {
54370
- const contents = `${JSON.stringify({ acknowledged: this.acknowledged, nextSequence: this.nextSequence })}
54474
+ const contents = `${JSON.stringify({ acknowledged: this.acknowledged, nextSequence: this.nextSequence, acknowledgedOffset: this.acknowledgedOffset })}
54371
54475
  `;
54372
54476
  const operation = this.saving.then(async () => {
54373
54477
  const temporary = `${this.statePath}.${process.pid}.${randomUUID7()}.tmp`;
@@ -55548,11 +55652,14 @@ var RunManager = class {
55548
55652
  runQueues = /* @__PURE__ */ new Map();
55549
55653
  interruptionRequests = /* @__PURE__ */ new Map();
55550
55654
  importTimer;
55655
+ importTask;
55656
+ importedSnapshots = /* @__PURE__ */ new Map();
55551
55657
  commandTimer;
55552
55658
  stopped = false;
55659
+ shutdown = new AbortController();
55553
55660
  async start() {
55554
55661
  if (typeof this.client.pendingRunCommands !== "function") return;
55555
- await this.syncImports();
55662
+ void this.syncImports();
55556
55663
  try {
55557
55664
  const commands = await this.client.pendingRunCommands();
55558
55665
  await Promise.all(commands.map((command3) => this.execute(command3, true)));
@@ -55868,7 +55975,14 @@ var RunManager = class {
55868
55975
  journal,
55869
55976
  adapter,
55870
55977
  baseline
55871
- );
55978
+ ).catch((error) => {
55979
+ if (!this.stopped) {
55980
+ console.error(
55981
+ `Run ${run.id} finalization failed:`,
55982
+ error instanceof Error ? error.message : error
55983
+ );
55984
+ }
55985
+ });
55872
55986
  const requestedAfterStart = this.interruptionRequests.get(run.id);
55873
55987
  if (requestedAfterStart)
55874
55988
  await this.interruptActive(active, requestedAfterStart);
@@ -55890,7 +56004,7 @@ var RunManager = class {
55890
56004
  baseline,
55891
56005
  finalCheckpoint
55892
56006
  );
55893
- await this.retry(
56007
+ await this.retryFinalization(
55894
56008
  () => this.client.reportRunCheckpoint(run.id, attemptId, {
55895
56009
  ...finalCheckpoint,
55896
56010
  diffPatch: comparison.rollbackPatch
@@ -55908,14 +56022,14 @@ var RunManager = class {
55908
56022
  ).catch(() => void 0);
55909
56023
  }
55910
56024
  }
55911
- await this.retry(
56025
+ await this.retryFinalization(
55912
56026
  () => this.client.finishRunAttempt(attemptId, {
55913
56027
  status: completion.status,
55914
56028
  finalOutput: completion.finalOutput,
55915
56029
  error: completion.error
55916
56030
  })
55917
56031
  );
55918
- await this.retry(
56032
+ await this.retryFinalization(
55919
56033
  () => this.client.completeRunCommand(
55920
56034
  command3.id,
55921
56035
  completion.status === "FAILED" ? "FAILED" : "SUCCEEDED",
@@ -55923,13 +56037,14 @@ var RunManager = class {
55923
56037
  )
55924
56038
  );
55925
56039
  } catch (error) {
55926
- await this.retry(
56040
+ if (this.stopped) return;
56041
+ await this.retryFinalization(
55927
56042
  () => this.client.finishRunAttempt(attemptId, {
55928
56043
  status: "FAILED",
55929
56044
  error: error instanceof Error ? error.message : String(error)
55930
56045
  })
55931
56046
  );
55932
- await this.retry(
56047
+ await this.retryFinalization(
55933
56048
  () => this.client.completeRunCommand(
55934
56049
  command3.id,
55935
56050
  "FAILED",
@@ -56212,10 +56327,22 @@ var RunManager = class {
56212
56327
  }
56213
56328
  return null;
56214
56329
  }
56215
- async syncImports() {
56330
+ syncImports() {
56331
+ if (this.stopped) return Promise.resolve();
56332
+ if (!this.importTask) {
56333
+ this.importTask = this.syncImportsInternal().finally(() => {
56334
+ this.importTask = void 0;
56335
+ });
56336
+ }
56337
+ return this.importTask;
56338
+ }
56339
+ async syncImportsInternal() {
56216
56340
  if (this.stopped) return;
56341
+ if (this.importTimer) clearTimeout(this.importTimer);
56342
+ this.importTimer = void 0;
56217
56343
  try {
56218
56344
  const codebases = await this.client.agentCodebases();
56345
+ if (this.stopped) return;
56219
56346
  const worktrees = codebases.flatMap(
56220
56347
  (codebase) => codebase.worktrees.map((worktree) => ({
56221
56348
  id: worktree.id,
@@ -56224,29 +56351,59 @@ var RunManager = class {
56224
56351
  }))
56225
56352
  );
56226
56353
  for (const adapter of this.adapters.values()) {
56354
+ if (this.stopped) return;
56227
56355
  try {
56228
56356
  const catalog = await adapter.catalog?.(worktrees);
56357
+ if (this.stopped) return;
56229
56358
  await this.client.reportRunProviderImportStatus(
56230
56359
  adapter.key,
56231
56360
  "SYNCING",
56232
56361
  void 0,
56233
56362
  { ...catalog, capabilities: adapter.capabilities }
56234
56363
  );
56364
+ if (this.stopped) return;
56235
56365
  const runs = await adapter.discover(worktrees);
56366
+ if (this.stopped) return;
56236
56367
  let batch = [];
56237
56368
  let batchBytes = 0;
56369
+ let snapshots = [];
56370
+ const upload = async () => {
56371
+ await this.client.importProviderRuns(adapter.key, batch);
56372
+ for (const [key, digest] of snapshots) {
56373
+ this.importedSnapshots.set(key, digest);
56374
+ }
56375
+ batch = [];
56376
+ batchBytes = 0;
56377
+ snapshots = [];
56378
+ };
56238
56379
  for (const run of runs) {
56239
- const bytes = Buffer.byteLength(JSON.stringify(run), "utf8");
56380
+ if (this.stopped) return;
56381
+ const serialized2 = JSON.stringify(run);
56382
+ const key = JSON.stringify([
56383
+ adapter.key,
56384
+ run.nativeId,
56385
+ run.worktreeId
56386
+ ]);
56387
+ const digest = createHash8("sha256").update(serialized2).digest("hex");
56388
+ const active = [
56389
+ "ACTIVE",
56390
+ "RUNNING",
56391
+ "STARTING",
56392
+ "IN_PROGRESS",
56393
+ "WAITING_FOR_ANSWER"
56394
+ ].includes(run.status?.toUpperCase() ?? "");
56395
+ if (!active && this.importedSnapshots.get(key) === digest) continue;
56396
+ const bytes = Buffer.byteLength(serialized2, "utf8");
56240
56397
  if (batch.length && batchBytes + bytes > 4 * 1024 * 1024) {
56241
- await this.client.importProviderRuns(adapter.key, batch);
56242
- batch = [];
56243
- batchBytes = 0;
56398
+ await upload();
56244
56399
  }
56245
56400
  batch.push(run);
56246
56401
  batchBytes += bytes;
56402
+ snapshots.push([key, digest]);
56247
56403
  }
56248
- await this.client.importProviderRuns(adapter.key, batch);
56404
+ await upload();
56249
56405
  } catch (error) {
56406
+ if (this.stopped) return;
56250
56407
  await this.client.reportRunProviderImportStatus(
56251
56408
  adapter.key,
56252
56409
  "FAILED",
@@ -56259,10 +56416,12 @@ var RunManager = class {
56259
56416
  }
56260
56417
  }
56261
56418
  } catch (error) {
56262
- console.error(
56263
- "Provider history sync failed:",
56264
- error instanceof Error ? error.message : error
56265
- );
56419
+ if (!this.stopped) {
56420
+ console.error(
56421
+ "Provider history sync failed:",
56422
+ error instanceof Error ? error.message : error
56423
+ );
56424
+ }
56266
56425
  } finally {
56267
56426
  if (!this.stopped) {
56268
56427
  this.importTimer = setTimeout(
@@ -56273,14 +56432,19 @@ var RunManager = class {
56273
56432
  }
56274
56433
  }
56275
56434
  }
56276
- async retry(operation, attempts = Infinity) {
56435
+ retryFinalization(operation) {
56436
+ return this.retry(operation, Infinity);
56437
+ }
56438
+ async retry(operation, attempts = MAX_AGENT_REQUEST_ATTEMPTS) {
56277
56439
  let delay3 = 1e3;
56278
56440
  for (let attempt = 1; ; attempt += 1) {
56279
56441
  try {
56280
56442
  return await operation();
56281
56443
  } catch (error) {
56282
- if (this.stopped || attempt >= attempts) throw error;
56283
- await new Promise((resolve11) => setTimeout(resolve11, delay3));
56444
+ if (this.stopped || attempt >= attempts || !isRetryableAgentError(error))
56445
+ throw error;
56446
+ await waitForAgentRetry(delay3, this.shutdown.signal);
56447
+ if (this.stopped) throw error;
56284
56448
  delay3 = Math.min(delay3 * 2, 3e4);
56285
56449
  }
56286
56450
  }
@@ -56293,14 +56457,16 @@ var RunManager = class {
56293
56457
  }
56294
56458
  async close() {
56295
56459
  this.stopped = true;
56460
+ this.shutdown.abort();
56296
56461
  if (this.importTimer) clearTimeout(this.importTimer);
56297
56462
  if (this.commandTimer) clearTimeout(this.commandTimer);
56298
56463
  for (const active of this.active.values()) {
56299
56464
  await active.handle.interrupt("PAUSED").catch(() => void 0);
56300
56465
  }
56301
- await Promise.allSettled(
56302
- this.adapters.values().map((adapter) => adapter.close?.())
56303
- );
56466
+ await Promise.allSettled([
56467
+ this.importTask,
56468
+ ...this.adapters.values().map((adapter) => adapter.close?.())
56469
+ ]);
56304
56470
  }
56305
56471
  };
56306
56472
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-development-environment/control-agent",
3
- "version": "0.0.129",
3
+ "version": "0.0.131",
4
4
  "description": "Control agent for the AI Development Environment",
5
5
  "license": "MIT",
6
6
  "repository": {