@ai-development-environment/control-agent 0.0.80 → 0.0.82

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 +168 -41
  2. package/package.json +1 -1
@@ -4184,7 +4184,7 @@ var require_cross_spawn = __commonJS({
4184
4184
  var cp3 = __require("child_process");
4185
4185
  var parse2 = require_parse();
4186
4186
  var enoent = require_enoent();
4187
- function spawn8(command3, args, options) {
4187
+ function spawn9(command3, args, options) {
4188
4188
  const parsed = parse2(command3, args, options);
4189
4189
  const spawned = cp3.spawn(parsed.command, parsed.args, parsed.options);
4190
4190
  enoent.hookChildProcess(spawned, parsed);
@@ -4196,8 +4196,8 @@ var require_cross_spawn = __commonJS({
4196
4196
  result.error = result.error || enoent.verifyENOENTSync(result.status, parsed);
4197
4197
  return result;
4198
4198
  }
4199
- module.exports = spawn8;
4200
- module.exports.spawn = spawn8;
4199
+ module.exports = spawn9;
4200
+ module.exports.spawn = spawn9;
4201
4201
  module.exports.sync = spawnSync2;
4202
4202
  module.exports._parse = parse2;
4203
4203
  module.exports._enoent = enoent;
@@ -5031,6 +5031,26 @@ var AgentGraphQLClient = class {
5031
5031
  })
5032
5032
  };
5033
5033
  }
5034
+ async ready() {
5035
+ const response = await fetch(`${this.server}/api/auth/config`, {
5036
+ headers: { ...this.headers },
5037
+ signal: AbortSignal.timeout(this.requestTimeoutMs)
5038
+ });
5039
+ const raw = await response.text();
5040
+ let body;
5041
+ try {
5042
+ body = raw ? JSON.parse(raw) : void 0;
5043
+ } catch {
5044
+ body = void 0;
5045
+ }
5046
+ if (!response.ok || typeof body?.mode !== "string") {
5047
+ const detail = `HTTP ${response.status} ${response.statusText}`.trim();
5048
+ throw new Error(
5049
+ !body && raw ? `${detail}: ${raw.slice(0, 500)}` : detail
5050
+ );
5051
+ }
5052
+ return { mode: body.mode };
5053
+ }
5034
5054
  async request(query, variables) {
5035
5055
  const response = await fetch(`${this.server}/api/graphql`, {
5036
5056
  method: "POST",
@@ -14286,12 +14306,16 @@ import { tmpdir as tmpdir5 } from "node:os";
14286
14306
  import { join as join12 } from "node:path";
14287
14307
 
14288
14308
  // src/runs/git-checkpoint.ts
14289
- import { execFile as execFile2 } from "node:child_process";
14309
+ import { execFile as execFile2, spawn as spawn6 } from "node:child_process";
14290
14310
  import { copyFile, mkdtemp as mkdtemp4, rm as rm7 } from "node:fs/promises";
14291
14311
  import { tmpdir as tmpdir4 } from "node:os";
14292
14312
  import { join as join11 } from "node:path";
14293
14313
  import { promisify as promisify2 } from "node:util";
14294
14314
  var execFileAsync = promisify2(execFile2);
14315
+ var PATCH_LIMIT = 2e6;
14316
+ var SUMMARY_LIMIT = 24e4;
14317
+ var MANIFEST_LIMIT = 2e6;
14318
+ var TRUNCATION_RESERVE = 200;
14295
14319
  async function git2(cwd, args, env) {
14296
14320
  const result = await execFileAsync("git", args, {
14297
14321
  cwd,
@@ -14308,24 +14332,111 @@ async function optionalGit(cwd, args) {
14308
14332
  return null;
14309
14333
  }
14310
14334
  }
14335
+ function cappedGit(cwd, args, limit) {
14336
+ const budget = limit - TRUNCATION_RESERVE;
14337
+ return new Promise((resolve8, reject) => {
14338
+ const child = spawn6("git", args, {
14339
+ cwd,
14340
+ env: {
14341
+ ...process.env,
14342
+ GIT_TERMINAL_PROMPT: "0",
14343
+ GIT_OPTIONAL_LOCKS: "0"
14344
+ },
14345
+ shell: false,
14346
+ stdio: ["ignore", "pipe", "pipe"]
14347
+ });
14348
+ const chunks = [];
14349
+ const errorChunks = [];
14350
+ let collected = 0;
14351
+ let errorCollected = 0;
14352
+ let truncated = false;
14353
+ let settled = false;
14354
+ child.stdout.on("data", (chunk) => {
14355
+ if (truncated) return;
14356
+ const remaining = budget - collected;
14357
+ if (chunk.length >= remaining) {
14358
+ chunks.push(chunk.subarray(0, remaining));
14359
+ collected = budget;
14360
+ truncated = true;
14361
+ child.stdout.destroy();
14362
+ if (child.exitCode === null && !child.killed) child.kill("SIGTERM");
14363
+ return;
14364
+ }
14365
+ chunks.push(chunk);
14366
+ collected += chunk.length;
14367
+ });
14368
+ child.stderr.on("data", (chunk) => {
14369
+ if (errorCollected >= 8192) return;
14370
+ errorChunks.push(chunk);
14371
+ errorCollected += chunk.length;
14372
+ });
14373
+ child.once("error", (error) => {
14374
+ if (settled) return;
14375
+ settled = true;
14376
+ reject(error);
14377
+ });
14378
+ child.once("close", (exitCode) => {
14379
+ if (settled) return;
14380
+ settled = true;
14381
+ if (!truncated && exitCode !== 0) {
14382
+ const message = Buffer.concat(errorChunks).toString("utf8").trim() || `git ${args[0]} exited with code ${exitCode}`;
14383
+ reject(new Error(message));
14384
+ return;
14385
+ }
14386
+ const output = Buffer.concat(chunks).toString("utf8");
14387
+ resolve8(
14388
+ truncated ? `${output.trimEnd()}
14389
+
14390
+ [Truncated after ${budget} bytes]` : output.trim()
14391
+ );
14392
+ });
14393
+ });
14394
+ }
14395
+ async function optionalCappedGit(cwd, args, limit) {
14396
+ try {
14397
+ return await cappedGit(cwd, args, limit) || null;
14398
+ } catch {
14399
+ return null;
14400
+ }
14401
+ }
14402
+ function manifestPayload(manifest) {
14403
+ let value = manifest;
14404
+ let json = JSON.stringify({ porcelainV2: value });
14405
+ while (json.length > MANIFEST_LIMIT && value.length > 0) {
14406
+ value = value.slice(
14407
+ 0,
14408
+ Math.floor(value.length * MANIFEST_LIMIT / json.length) - 1
14409
+ );
14410
+ json = JSON.stringify({ porcelainV2: value });
14411
+ }
14412
+ return json;
14413
+ }
14311
14414
  async function compareGitCheckpoint(cwd, target2, current) {
14312
14415
  if (!target2.worktreeTree || !current.worktreeTree) {
14313
14416
  throw new Error("The worktree checkpoint is incomplete");
14314
14417
  }
14315
- const worktreePatch = await git2(cwd, [
14316
- "diff",
14317
- "--binary",
14318
- "--find-renames",
14319
- target2.worktreeTree,
14320
- current.worktreeTree
14321
- ]);
14322
- const indexPatch = target2.indexTree && current.indexTree ? await git2(cwd, [
14323
- "diff",
14324
- "--binary",
14325
- "--find-renames",
14326
- target2.indexTree,
14327
- current.indexTree
14328
- ]) : "";
14418
+ const worktreePatch = await cappedGit(
14419
+ cwd,
14420
+ [
14421
+ "diff",
14422
+ "--binary",
14423
+ "--find-renames",
14424
+ target2.worktreeTree,
14425
+ current.worktreeTree
14426
+ ],
14427
+ PATCH_LIMIT
14428
+ );
14429
+ const indexPatch = target2.indexTree && current.indexTree ? await cappedGit(
14430
+ cwd,
14431
+ [
14432
+ "diff",
14433
+ "--binary",
14434
+ "--find-renames",
14435
+ target2.indexTree,
14436
+ current.indexTree
14437
+ ],
14438
+ PATCH_LIMIT
14439
+ ) : "";
14329
14440
  const upstream = await optionalGit(cwd, ["rev-parse", "@{upstream}"]);
14330
14441
  const pushedCount = target2.headSha && upstream ? Number(
14331
14442
  await optionalGit(cwd, [
@@ -14342,7 +14453,7 @@ ${worktreePatch}`,
14342
14453
  indexPatch && `Index changes that will be undone:
14343
14454
 
14344
14455
  ${indexPatch}`
14345
- ].filter(Boolean).join("\n\n").slice(0, 2e6),
14456
+ ].filter(Boolean).join("\n\n").slice(0, PATCH_LIMIT),
14346
14457
  pushedCommitWarning: pushedCount > 0 ? `${pushedCount} commit${pushedCount === 1 ? "" : "s"} after this question appear on the upstream branch. Remote refs will not be changed.` : null
14347
14458
  };
14348
14459
  }
@@ -14401,9 +14512,21 @@ async function captureGitCheckpoint(cwd, runId, kind) {
14401
14512
  ]);
14402
14513
  const upstreamSha = await optionalGit(cwd, ["rev-parse", "@{upstream}"]);
14403
14514
  const indexTree = await optionalGit(cwd, ["write-tree"]);
14404
- const manifest = await optionalGit(cwd, ["status", "--porcelain=v2", "-z"]);
14405
- const staged = await optionalGit(cwd, ["diff", "--cached", "--stat", "HEAD"]);
14406
- const unstaged = await optionalGit(cwd, ["diff", "--stat", "HEAD"]);
14515
+ const manifest = await optionalCappedGit(
14516
+ cwd,
14517
+ ["status", "--porcelain=v2", "-z"],
14518
+ MANIFEST_LIMIT
14519
+ );
14520
+ const staged = await optionalCappedGit(
14521
+ cwd,
14522
+ ["diff", "--cached", "--stat", "HEAD"],
14523
+ SUMMARY_LIMIT
14524
+ );
14525
+ const unstaged = await optionalCappedGit(
14526
+ cwd,
14527
+ ["diff", "--stat", "HEAD"],
14528
+ SUMMARY_LIMIT
14529
+ );
14407
14530
  const directory = await mkdtemp4(join11(tmpdir4(), "aide-run-index-"));
14408
14531
  let worktreeTree = null;
14409
14532
  let refName = null;
@@ -14451,17 +14574,15 @@ async function captureGitCheckpoint(cwd, runId, kind) {
14451
14574
  indexTree,
14452
14575
  worktreeTree,
14453
14576
  refName,
14454
- manifestJson: JSON.stringify({ porcelainV2: manifest ?? "" }),
14577
+ manifestJson: manifestPayload(manifest ?? ""),
14455
14578
  diffSummary: [staged && `Staged:
14456
14579
  ${staged}`, unstaged && `Working tree:
14457
14580
  ${unstaged}`].filter(Boolean).join("\n\n") || null,
14458
- diffPatch: headSha && worktreeTree ? (await git2(cwd, [
14459
- "diff",
14460
- "--binary",
14461
- "--find-renames",
14462
- headSha,
14463
- worktreeTree
14464
- ])).slice(0, 2e6) || null : null
14581
+ diffPatch: headSha && worktreeTree ? await cappedGit(
14582
+ cwd,
14583
+ ["diff", "--binary", "--find-renames", headSha, worktreeTree],
14584
+ PATCH_LIMIT
14585
+ ) || null : null
14465
14586
  };
14466
14587
  }
14467
14588
 
@@ -14576,7 +14697,7 @@ import { createWriteStream as createWriteStream2, watch } from "node:fs";
14576
14697
  import { mkdtemp as mkdtemp6, open as open2, readFile as readFile8, realpath as realpath8, rm as rm9, stat as stat10 } from "node:fs/promises";
14577
14698
  import { tmpdir as tmpdir6 } from "node:os";
14578
14699
  import { basename as basename5, dirname as dirname7, isAbsolute as isAbsolute6, join as join13, relative as relative7 } from "node:path";
14579
- import { spawn as spawn6 } from "node:child_process";
14700
+ import { spawn as spawn7 } from "node:child_process";
14580
14701
  var successfulProcess8 = {
14581
14702
  exitCode: 0,
14582
14703
  signal: null,
@@ -15576,7 +15697,7 @@ function imageContentType(path) {
15576
15697
  }
15577
15698
  async function writeGitObject(folder, specification, destination, timeoutMs, signal) {
15578
15699
  await new Promise((resolvePromise, rejectPromise) => {
15579
- const child = spawn6(
15700
+ const child = spawn7(
15580
15701
  "git",
15581
15702
  ["-C", folder, "cat-file", "blob", specification],
15582
15703
  { stdio: ["ignore", "pipe", "pipe"] }
@@ -43515,7 +43636,7 @@ var ClaudeAdapter = class {
43515
43636
  // src/runs/codex-adapter.ts
43516
43637
  import {
43517
43638
  execFile as execFile3,
43518
- spawn as spawn7
43639
+ spawn as spawn8
43519
43640
  } from "node:child_process";
43520
43641
  import { mkdtemp as mkdtemp7, rm as rm12, writeFile as writeFile8 } from "node:fs/promises";
43521
43642
  import { tmpdir as tmpdir7 } from "node:os";
@@ -43604,7 +43725,7 @@ var CodexAppServer = class {
43604
43725
  const executable = this.executable();
43605
43726
  const modelCatalogPath = await this.createBundledModelCatalog(executable);
43606
43727
  const modelCatalogDirectory = this.modelCatalogDirectory;
43607
- const child = spawn7(executable, codexAppServerArgs(modelCatalogPath), {
43728
+ const child = spawn8(executable, codexAppServerArgs(modelCatalogPath), {
43608
43729
  stdio: ["pipe", "pipe", "pipe"],
43609
43730
  env: process.env
43610
43731
  });
@@ -51304,7 +51425,7 @@ async function waitForServer(client2, timeoutMs, signal, dependencies) {
51304
51425
  let lastError;
51305
51426
  while (!signal.aborted && Date.now() < deadline) {
51306
51427
  try {
51307
- await client2.health();
51428
+ await client2.ready();
51308
51429
  return;
51309
51430
  } catch (error) {
51310
51431
  lastError = error;
@@ -51346,10 +51467,15 @@ async function prepareDevelopmentAgent(options, signal, dependencies = defaultDe
51346
51467
  }
51347
51468
  } catch {
51348
51469
  }
51349
- const enrollment2 = await anonymousClient.createEnrollmentToken();
51470
+ const enrollmentToken = options.enrollmentToken?.trim();
51471
+ if (!enrollmentToken) {
51472
+ throw new Error(
51473
+ "The development agent needs a one-time enrollment token. Create one on the Agents page and set CONTROL_AGENT_DEV_ENROLLMENT_TOKEN."
51474
+ );
51475
+ }
51350
51476
  const response = await anonymousClient.enroll({
51351
51477
  ...inventory,
51352
- enrollmentToken: enrollment2.createAgentEnrollmentToken.token,
51478
+ enrollmentToken,
51353
51479
  name
51354
51480
  });
51355
51481
  const config = {
@@ -51583,10 +51709,10 @@ async function doctor() {
51583
51709
  null,
51584
51710
  1e4,
51585
51711
  config?.headers
51586
- ).health();
51712
+ ).ready();
51587
51713
  return {
51588
- ok: health.health === "ok",
51589
- detail: `${endpoint.kind} ${endpoint.server}: ${health.health}`
51714
+ ok: true,
51715
+ detail: `${endpoint.kind} ${endpoint.server}: ready (${health.mode})`
51590
51716
  };
51591
51717
  } catch (error) {
51592
51718
  return {
@@ -51633,7 +51759,8 @@ async function main() {
51633
51759
  {
51634
51760
  server,
51635
51761
  websocketServer: options["websocket-server"] ?? process.env.CONTROL_AGENT_DEV_WEBSOCKET_SERVER ?? process.env.NEXT_PUBLIC_AGENT_WS_URL,
51636
- name: options.name
51762
+ name: options.name,
51763
+ enrollmentToken: options["enrollment-token"] ?? process.env.CONTROL_AGENT_DEV_ENROLLMENT_TOKEN
51637
51764
  },
51638
51765
  controller.signal
51639
51766
  );
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ai-development-environment/control-agent",
3
- "version": "0.0.80",
3
+ "version": "0.0.82",
4
4
  "description": "Control agent for the AI Development Environment",
5
5
  "license": "MIT",
6
6
  "repository": {