@ai-development-environment/control-agent 0.0.54 → 0.0.56
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/dist/control-agent.js +342 -60
- package/package.json +5 -4
package/dist/control-agent.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
const require = createRequire(import.meta.url);
|
|
2
4
|
var __create = Object.create;
|
|
3
5
|
var __defProp = Object.defineProperty;
|
|
4
6
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
@@ -3728,15 +3730,15 @@ var require_windows = __commonJS({
|
|
|
3728
3730
|
}
|
|
3729
3731
|
return false;
|
|
3730
3732
|
}
|
|
3731
|
-
function checkStat(
|
|
3732
|
-
if (!
|
|
3733
|
+
function checkStat(stat10, path, options) {
|
|
3734
|
+
if (!stat10.isSymbolicLink() && !stat10.isFile()) {
|
|
3733
3735
|
return false;
|
|
3734
3736
|
}
|
|
3735
3737
|
return checkPathExt(path, options);
|
|
3736
3738
|
}
|
|
3737
3739
|
function isexe(path, options, cb2) {
|
|
3738
|
-
fs.stat(path, function(er2,
|
|
3739
|
-
cb2(er2, er2 ? false : checkStat(
|
|
3740
|
+
fs.stat(path, function(er2, stat10) {
|
|
3741
|
+
cb2(er2, er2 ? false : checkStat(stat10, path, options));
|
|
3740
3742
|
});
|
|
3741
3743
|
}
|
|
3742
3744
|
function sync(path, options) {
|
|
@@ -3752,20 +3754,20 @@ var require_mode = __commonJS({
|
|
|
3752
3754
|
isexe.sync = sync;
|
|
3753
3755
|
var fs = __require("fs");
|
|
3754
3756
|
function isexe(path, options, cb2) {
|
|
3755
|
-
fs.stat(path, function(er2,
|
|
3756
|
-
cb2(er2, er2 ? false : checkStat(
|
|
3757
|
+
fs.stat(path, function(er2, stat10) {
|
|
3758
|
+
cb2(er2, er2 ? false : checkStat(stat10, options));
|
|
3757
3759
|
});
|
|
3758
3760
|
}
|
|
3759
3761
|
function sync(path, options) {
|
|
3760
3762
|
return checkStat(fs.statSync(path), options);
|
|
3761
3763
|
}
|
|
3762
|
-
function checkStat(
|
|
3763
|
-
return
|
|
3764
|
+
function checkStat(stat10, options) {
|
|
3765
|
+
return stat10.isFile() && checkMode(stat10, options);
|
|
3764
3766
|
}
|
|
3765
|
-
function checkMode(
|
|
3766
|
-
var mod =
|
|
3767
|
-
var uid =
|
|
3768
|
-
var gid =
|
|
3767
|
+
function checkMode(stat10, options) {
|
|
3768
|
+
var mod = stat10.mode;
|
|
3769
|
+
var uid = stat10.uid;
|
|
3770
|
+
var gid = stat10.gid;
|
|
3769
3771
|
var myUid = options.uid !== void 0 ? options.uid : process.getuid && process.getuid();
|
|
3770
3772
|
var myGid = options.gid !== void 0 ? options.gid : process.getgid && process.getgid();
|
|
3771
3773
|
var u = parseInt("100", 8);
|
|
@@ -5164,6 +5166,24 @@ var AgentGraphQLClient = class {
|
|
|
5164
5166
|
}
|
|
5165
5167
|
);
|
|
5166
5168
|
}
|
|
5169
|
+
async diskSpaceConfiguration() {
|
|
5170
|
+
const data = await this.request(`query AgentDiskSpaceConfiguration {
|
|
5171
|
+
agentDiskSpaceConfiguration {
|
|
5172
|
+
enabled pollIntervalSeconds baseRepoDirectory
|
|
5173
|
+
derivedDataLocationMode derivedDataPath
|
|
5174
|
+
worktrees { id folder }
|
|
5175
|
+
}
|
|
5176
|
+
}`);
|
|
5177
|
+
return data.agentDiskSpaceConfiguration;
|
|
5178
|
+
}
|
|
5179
|
+
reportDiskSpace(input) {
|
|
5180
|
+
return this.request(
|
|
5181
|
+
`mutation ReportAgentDiskSpace($input: AgentDiskSpaceReportInput!) {
|
|
5182
|
+
reportAgentDiskSpace(input: $input)
|
|
5183
|
+
}`,
|
|
5184
|
+
{ input }
|
|
5185
|
+
);
|
|
5186
|
+
}
|
|
5167
5187
|
async pendingJobs(agentId) {
|
|
5168
5188
|
const data = await this.request(
|
|
5169
5189
|
`query PendingJobs($agentId: ID!) {
|
|
@@ -5592,6 +5612,10 @@ function nullableString(value, name) {
|
|
|
5592
5612
|
if (value === null) return null;
|
|
5593
5613
|
return stringValue2(value, name);
|
|
5594
5614
|
}
|
|
5615
|
+
function optionalNullableString(value, name) {
|
|
5616
|
+
if (value === void 0 || value === null) return null;
|
|
5617
|
+
return stringValue2(value, name);
|
|
5618
|
+
}
|
|
5595
5619
|
function exactKeys(value, allowed, name) {
|
|
5596
5620
|
const unexpected = Object.keys(value).find((key) => !allowed.includes(key));
|
|
5597
5621
|
if (unexpected) throw new Error(`Unexpected ${name} field: ${unexpected}`);
|
|
@@ -5621,6 +5645,44 @@ function target(value, index) {
|
|
|
5621
5645
|
)
|
|
5622
5646
|
};
|
|
5623
5647
|
}
|
|
5648
|
+
function deleteTarget(value, index) {
|
|
5649
|
+
const item = objectValue2(value, `build data delete targets[${index}]`);
|
|
5650
|
+
exactKeys(
|
|
5651
|
+
item,
|
|
5652
|
+
["path", "rootPath", "name", "kind", "worktreeId", "worktreePath"],
|
|
5653
|
+
"build data delete target"
|
|
5654
|
+
);
|
|
5655
|
+
const kind = item.kind;
|
|
5656
|
+
if (kind !== void 0 && !["PROJECT", "PENDING", "SHARED_CACHE", "DEVICE_SUPPORT"].includes(kind)) {
|
|
5657
|
+
throw new Error(`build data delete targets[${index}].kind is invalid`);
|
|
5658
|
+
}
|
|
5659
|
+
return {
|
|
5660
|
+
path: stringValue2(item.path, `build data delete targets[${index}].path`),
|
|
5661
|
+
rootPath: stringValue2(
|
|
5662
|
+
item.rootPath,
|
|
5663
|
+
`build data delete targets[${index}].rootPath`
|
|
5664
|
+
),
|
|
5665
|
+
...item.name === void 0 ? {} : {
|
|
5666
|
+
name: stringValue2(
|
|
5667
|
+
item.name,
|
|
5668
|
+
`build data delete targets[${index}].name`
|
|
5669
|
+
)
|
|
5670
|
+
},
|
|
5671
|
+
...kind === void 0 ? {} : { kind },
|
|
5672
|
+
...item.worktreeId === void 0 ? {} : {
|
|
5673
|
+
worktreeId: optionalNullableString(
|
|
5674
|
+
item.worktreeId,
|
|
5675
|
+
`build data delete targets[${index}].worktreeId`
|
|
5676
|
+
)
|
|
5677
|
+
},
|
|
5678
|
+
...item.worktreePath === void 0 ? {} : {
|
|
5679
|
+
worktreePath: optionalNullableString(
|
|
5680
|
+
item.worktreePath,
|
|
5681
|
+
`build data delete targets[${index}].worktreePath`
|
|
5682
|
+
)
|
|
5683
|
+
}
|
|
5684
|
+
};
|
|
5685
|
+
}
|
|
5624
5686
|
function buildDataScanPayload(value) {
|
|
5625
5687
|
const payload = objectValue2(value, "build data scan payload");
|
|
5626
5688
|
exactKeys(payload, ["mode", "path", "worktrees"], "build data scan payload");
|
|
@@ -5651,6 +5713,23 @@ function buildDataTargetsPayload(value) {
|
|
|
5651
5713
|
}
|
|
5652
5714
|
return { targets: payload.targets.map(target) };
|
|
5653
5715
|
}
|
|
5716
|
+
function buildDataDeletePayload(value) {
|
|
5717
|
+
const payload = objectValue2(value, "build data delete payload");
|
|
5718
|
+
exactKeys(payload, ["targets", "source"], "build data delete payload");
|
|
5719
|
+
if (!Array.isArray(payload.targets) || payload.targets.length > 1e4) {
|
|
5720
|
+
throw new Error(
|
|
5721
|
+
"build data delete targets must be an array of at most 10,000 items"
|
|
5722
|
+
);
|
|
5723
|
+
}
|
|
5724
|
+
const source = payload.source ?? "USER";
|
|
5725
|
+
if (source !== "USER" && source !== "AUTOMATIC") {
|
|
5726
|
+
throw new Error("build data delete source is invalid");
|
|
5727
|
+
}
|
|
5728
|
+
return {
|
|
5729
|
+
targets: payload.targets.map(deleteTarget),
|
|
5730
|
+
source
|
|
5731
|
+
};
|
|
5732
|
+
}
|
|
5654
5733
|
|
|
5655
5734
|
// ../agent-contract/src/codebases.ts
|
|
5656
5735
|
var CODEBASE_BROWSE_JOB_KIND = "codebase.browse";
|
|
@@ -8987,7 +9066,15 @@ async function runCcusage(payload, timeoutMs, signal, onLog) {
|
|
|
8987
9066
|
}
|
|
8988
9067
|
|
|
8989
9068
|
// src/handlers/build-data.ts
|
|
8990
|
-
import {
|
|
9069
|
+
import {
|
|
9070
|
+
lstat,
|
|
9071
|
+
opendir,
|
|
9072
|
+
readdir as readdir2,
|
|
9073
|
+
realpath as realpath2,
|
|
9074
|
+
rm as rm4,
|
|
9075
|
+
stat as stat3,
|
|
9076
|
+
statfs
|
|
9077
|
+
} from "node:fs/promises";
|
|
8991
9078
|
import { homedir as homedir4 } from "node:os";
|
|
8992
9079
|
import { basename as basename2, dirname as dirname2, isAbsolute, join as join4, resolve } from "node:path";
|
|
8993
9080
|
var successfulProcess2 = {
|
|
@@ -9063,10 +9150,13 @@ async function scanRoot(configuredRoot, timeoutMs, signal) {
|
|
|
9063
9150
|
};
|
|
9064
9151
|
}
|
|
9065
9152
|
const entries = [];
|
|
9153
|
+
const rootStats = await stat3(rootPath2);
|
|
9154
|
+
const volumeId = String(rootStats.dev);
|
|
9066
9155
|
for (const child of children) {
|
|
9067
9156
|
signal.throwIfAborted();
|
|
9068
9157
|
if (!child.isDirectory()) continue;
|
|
9069
9158
|
const path = join4(rootPath2, child.name);
|
|
9159
|
+
const information = await lstat(path);
|
|
9070
9160
|
const projectPath = await workspacePath(
|
|
9071
9161
|
join4(path, "info.plist"),
|
|
9072
9162
|
timeoutMs,
|
|
@@ -9077,7 +9167,9 @@ async function scanRoot(configuredRoot, timeoutMs, signal) {
|
|
|
9077
9167
|
rootPath: rootPath2,
|
|
9078
9168
|
name: child.name,
|
|
9079
9169
|
kind: projectPath ? "PROJECT" : child.name.toLocaleLowerCase().endsWith(".noindex") ? "SHARED_CACHE" : "PENDING",
|
|
9080
|
-
workspacePath: projectPath
|
|
9170
|
+
workspacePath: projectPath,
|
|
9171
|
+
modifiedAt: information.mtime.toISOString(),
|
|
9172
|
+
volumeId
|
|
9081
9173
|
});
|
|
9082
9174
|
}
|
|
9083
9175
|
entries.sort((first, second) => first.name.localeCompare(second.name));
|
|
@@ -9109,7 +9201,9 @@ async function scanDeviceSupport(signal) {
|
|
|
9109
9201
|
rootPath: rootPath2,
|
|
9110
9202
|
name: child.name,
|
|
9111
9203
|
kind: "DEVICE_SUPPORT",
|
|
9112
|
-
workspacePath: null
|
|
9204
|
+
workspacePath: null,
|
|
9205
|
+
modifiedAt: null,
|
|
9206
|
+
volumeId: null
|
|
9113
9207
|
})).sort((first, second) => first.name.localeCompare(second.name)),
|
|
9114
9208
|
warning: null
|
|
9115
9209
|
};
|
|
@@ -9203,7 +9297,7 @@ var sizeBuildData = async (rawPayload, _timeoutMs, signal) => {
|
|
|
9203
9297
|
return { ...successfulProcess2, sizes };
|
|
9204
9298
|
};
|
|
9205
9299
|
var deleteBuildData = async (rawPayload, _timeoutMs, signal) => {
|
|
9206
|
-
const payload =
|
|
9300
|
+
const payload = buildDataDeletePayload(rawPayload);
|
|
9207
9301
|
const deleted = [];
|
|
9208
9302
|
for (const target2 of payload.targets) {
|
|
9209
9303
|
signal.throwIfAborted();
|
|
@@ -9230,9 +9324,120 @@ var deleteBuildData = async (rawPayload, _timeoutMs, signal) => {
|
|
|
9230
9324
|
}
|
|
9231
9325
|
return { ...successfulProcess2, deleted };
|
|
9232
9326
|
};
|
|
9327
|
+
async function sharedCapacityId(canonicalPath, volumeId, signal) {
|
|
9328
|
+
try {
|
|
9329
|
+
const result = await captureCommand({
|
|
9330
|
+
command: "/usr/sbin/diskutil",
|
|
9331
|
+
args: ["info", "-plist", canonicalPath],
|
|
9332
|
+
timeoutMs: 5e3,
|
|
9333
|
+
signal
|
|
9334
|
+
});
|
|
9335
|
+
signal.throwIfAborted();
|
|
9336
|
+
if (result.exitCode !== 0) return volumeId;
|
|
9337
|
+
const information = parsePlist(result.stdout);
|
|
9338
|
+
if (!information || typeof information !== "object") return volumeId;
|
|
9339
|
+
const container = information.APFSContainerReference;
|
|
9340
|
+
return typeof container === "string" && container.trim() ? `apfs:${container.trim()}` : volumeId;
|
|
9341
|
+
} catch {
|
|
9342
|
+
signal.throwIfAborted();
|
|
9343
|
+
return volumeId;
|
|
9344
|
+
}
|
|
9345
|
+
}
|
|
9346
|
+
async function inspectVolume(configuredPath, role, signal) {
|
|
9347
|
+
signal.throwIfAborted();
|
|
9348
|
+
const canonicalPath = await realpath2(configuredPath);
|
|
9349
|
+
const [information, filesystem] = await Promise.all([
|
|
9350
|
+
stat3(canonicalPath),
|
|
9351
|
+
statfs(canonicalPath, { bigint: true })
|
|
9352
|
+
]);
|
|
9353
|
+
const id2 = String(information.dev);
|
|
9354
|
+
return {
|
|
9355
|
+
canonicalPath,
|
|
9356
|
+
volume: {
|
|
9357
|
+
id: id2,
|
|
9358
|
+
capacityId: id2,
|
|
9359
|
+
totalBytes: Number(filesystem.blocks * filesystem.bsize),
|
|
9360
|
+
freeBytes: Number(filesystem.bavail * filesystem.bsize),
|
|
9361
|
+
roles: /* @__PURE__ */ new Set([role]),
|
|
9362
|
+
paths: /* @__PURE__ */ new Set([canonicalPath])
|
|
9363
|
+
}
|
|
9364
|
+
};
|
|
9365
|
+
}
|
|
9366
|
+
async function collectAgentDiskSpace(configuration, signal) {
|
|
9367
|
+
const scanPayload = buildDataScanPayload({
|
|
9368
|
+
mode: configuration.derivedDataLocationMode,
|
|
9369
|
+
path: configuration.derivedDataPath,
|
|
9370
|
+
worktrees: configuration.worktrees
|
|
9371
|
+
});
|
|
9372
|
+
const roots = await configuredRoots(scanPayload);
|
|
9373
|
+
const requested = [
|
|
9374
|
+
{ path: "/", role: "MAIN" },
|
|
9375
|
+
...configuration.baseRepoDirectory ? [{ path: configuration.baseRepoDirectory, role: "BASE_REPO" }] : [],
|
|
9376
|
+
...roots.map((path) => ({ path, role: "DERIVED_DATA" }))
|
|
9377
|
+
];
|
|
9378
|
+
const warnings = [];
|
|
9379
|
+
const volumes = /* @__PURE__ */ new Map();
|
|
9380
|
+
for (const request of requested) {
|
|
9381
|
+
signal.throwIfAborted();
|
|
9382
|
+
try {
|
|
9383
|
+
const inspected = await inspectVolume(request.path, request.role, signal);
|
|
9384
|
+
const existing = volumes.get(inspected.volume.id);
|
|
9385
|
+
if (existing) {
|
|
9386
|
+
existing.roles.add(request.role);
|
|
9387
|
+
existing.paths.add(inspected.canonicalPath);
|
|
9388
|
+
existing.totalBytes = inspected.volume.totalBytes;
|
|
9389
|
+
existing.freeBytes = inspected.volume.freeBytes;
|
|
9390
|
+
} else {
|
|
9391
|
+
inspected.volume.capacityId = await sharedCapacityId(
|
|
9392
|
+
inspected.canonicalPath,
|
|
9393
|
+
inspected.volume.id,
|
|
9394
|
+
signal
|
|
9395
|
+
);
|
|
9396
|
+
volumes.set(inspected.volume.id, inspected.volume);
|
|
9397
|
+
}
|
|
9398
|
+
} catch (error) {
|
|
9399
|
+
warnings.push(`${request.path}: ${errorMessage(error)}`);
|
|
9400
|
+
}
|
|
9401
|
+
}
|
|
9402
|
+
const entries = [];
|
|
9403
|
+
const scannedRoots = /* @__PURE__ */ new Set();
|
|
9404
|
+
for (const root of roots) {
|
|
9405
|
+
signal.throwIfAborted();
|
|
9406
|
+
let canonical = root;
|
|
9407
|
+
try {
|
|
9408
|
+
canonical = await realpath2(root);
|
|
9409
|
+
} catch {
|
|
9410
|
+
}
|
|
9411
|
+
if (scannedRoots.has(canonical)) continue;
|
|
9412
|
+
scannedRoots.add(canonical);
|
|
9413
|
+
const result = await scanRoot(root, 45e3, signal);
|
|
9414
|
+
if (result.warning) warnings.push(result.warning);
|
|
9415
|
+
for (const entry of result.entries) {
|
|
9416
|
+
if (!entry.modifiedAt || !entry.volumeId) continue;
|
|
9417
|
+
entries.push({
|
|
9418
|
+
...entry,
|
|
9419
|
+
modifiedAt: entry.modifiedAt,
|
|
9420
|
+
volumeId: entry.volumeId
|
|
9421
|
+
});
|
|
9422
|
+
}
|
|
9423
|
+
}
|
|
9424
|
+
return {
|
|
9425
|
+
observedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
9426
|
+
volumes: [...volumes.values()].map((volume) => ({
|
|
9427
|
+
id: volume.id,
|
|
9428
|
+
capacityId: volume.capacityId,
|
|
9429
|
+
totalBytes: volume.totalBytes,
|
|
9430
|
+
freeBytes: volume.freeBytes,
|
|
9431
|
+
roles: [...volume.roles],
|
|
9432
|
+
paths: [...volume.paths]
|
|
9433
|
+
})),
|
|
9434
|
+
entries,
|
|
9435
|
+
warnings: [...new Set(warnings)]
|
|
9436
|
+
};
|
|
9437
|
+
}
|
|
9233
9438
|
|
|
9234
9439
|
// src/handlers/codebases.ts
|
|
9235
|
-
import { readdir as readdir3, realpath as realpath3, stat as
|
|
9440
|
+
import { readdir as readdir3, realpath as realpath3, stat as stat4 } from "node:fs/promises";
|
|
9236
9441
|
import { homedir as homedir5 } from "node:os";
|
|
9237
9442
|
import { dirname as dirname3, join as join5, resolve as resolve2 } from "node:path";
|
|
9238
9443
|
var successfulProcess3 = {
|
|
@@ -9311,7 +9516,7 @@ function baseSnapshot(folder) {
|
|
|
9311
9516
|
}
|
|
9312
9517
|
async function fetchedAt(commonDirectory) {
|
|
9313
9518
|
try {
|
|
9314
|
-
return (await
|
|
9519
|
+
return (await stat4(join5(commonDirectory, "FETCH_HEAD"))).mtime.toISOString();
|
|
9315
9520
|
} catch {
|
|
9316
9521
|
return null;
|
|
9317
9522
|
}
|
|
@@ -9322,7 +9527,7 @@ async function inspectCodebaseProcess(selectedFolder, timeoutMs, signal, expecte
|
|
|
9322
9527
|
let selected;
|
|
9323
9528
|
try {
|
|
9324
9529
|
selected = await realpath3(fallbackFolder);
|
|
9325
|
-
if (!(await
|
|
9530
|
+
if (!(await stat4(selected)).isDirectory())
|
|
9326
9531
|
throw new Error("Folder is not a directory");
|
|
9327
9532
|
} catch (error) {
|
|
9328
9533
|
return {
|
|
@@ -9492,7 +9697,7 @@ var browseCodebaseDirectories = async (payload) => {
|
|
|
9492
9697
|
const input = codebaseBrowsePayload(payload);
|
|
9493
9698
|
const homePath = await realpath3(homedir5());
|
|
9494
9699
|
const path = await realpath3(input.path ? resolve2(input.path) : homePath);
|
|
9495
|
-
if (!(await
|
|
9700
|
+
if (!(await stat4(path)).isDirectory())
|
|
9496
9701
|
throw new Error("Path is not a directory");
|
|
9497
9702
|
const candidates = await readdir3(path, { withFileTypes: true });
|
|
9498
9703
|
const entries = [];
|
|
@@ -9506,7 +9711,7 @@ var browseCodebaseDirectories = async (payload) => {
|
|
|
9506
9711
|
} else if (candidate.isSymbolicLink()) {
|
|
9507
9712
|
try {
|
|
9508
9713
|
const target2 = join5(path, candidate.name);
|
|
9509
|
-
if ((await
|
|
9714
|
+
if ((await stat4(target2)).isDirectory()) {
|
|
9510
9715
|
entries.push({
|
|
9511
9716
|
name: candidate.name,
|
|
9512
9717
|
path: target2,
|
|
@@ -10115,7 +10320,7 @@ import {
|
|
|
10115
10320
|
readdir as readdir4,
|
|
10116
10321
|
rename as rename2,
|
|
10117
10322
|
rm as rm5,
|
|
10118
|
-
stat as
|
|
10323
|
+
stat as stat5,
|
|
10119
10324
|
writeFile as writeFile4
|
|
10120
10325
|
} from "node:fs/promises";
|
|
10121
10326
|
import { homedir as homedir6 } from "node:os";
|
|
@@ -10174,7 +10379,7 @@ var PROJECT_ROOTS = {
|
|
|
10174
10379
|
};
|
|
10175
10380
|
async function directoryExists(path) {
|
|
10176
10381
|
try {
|
|
10177
|
-
return (await
|
|
10382
|
+
return (await stat5(path)).isDirectory();
|
|
10178
10383
|
} catch {
|
|
10179
10384
|
return false;
|
|
10180
10385
|
}
|
|
@@ -10508,7 +10713,7 @@ var applySkills = async (payload) => {
|
|
|
10508
10713
|
};
|
|
10509
10714
|
|
|
10510
10715
|
// src/handlers/runs.ts
|
|
10511
|
-
import { readFile as readFile4, readdir as readdir5, stat as
|
|
10716
|
+
import { readFile as readFile4, readdir as readdir5, stat as stat6 } from "node:fs/promises";
|
|
10512
10717
|
import { homedir as homedir7 } from "node:os";
|
|
10513
10718
|
import { join as join7 } from "node:path";
|
|
10514
10719
|
var successfulProcess5 = {
|
|
@@ -10519,7 +10724,7 @@ var successfulProcess5 = {
|
|
|
10519
10724
|
};
|
|
10520
10725
|
async function fileExists(path) {
|
|
10521
10726
|
try {
|
|
10522
|
-
return (await
|
|
10727
|
+
return (await stat6(path)).isFile();
|
|
10523
10728
|
} catch {
|
|
10524
10729
|
return false;
|
|
10525
10730
|
}
|
|
@@ -10574,7 +10779,7 @@ var readRunSession = async (payload) => {
|
|
|
10574
10779
|
`No ${input.provider === "CLAUDE" ? "Claude" : "Codex"} session file found for this run on this agent`
|
|
10575
10780
|
);
|
|
10576
10781
|
}
|
|
10577
|
-
const { size } = await
|
|
10782
|
+
const { size } = await stat6(path);
|
|
10578
10783
|
if (size > MAX_RUN_SESSION_FILE_BYTES) {
|
|
10579
10784
|
throw new Error(
|
|
10580
10785
|
`Session file is too large to export (${size} bytes exceeds the ${MAX_RUN_SESSION_FILE_BYTES} byte limit)`
|
|
@@ -10594,7 +10799,7 @@ import {
|
|
|
10594
10799
|
readFile as readFile6,
|
|
10595
10800
|
realpath as realpath6,
|
|
10596
10801
|
rm as rm8,
|
|
10597
|
-
stat as
|
|
10802
|
+
stat as stat8,
|
|
10598
10803
|
writeFile as writeFile6
|
|
10599
10804
|
} from "node:fs/promises";
|
|
10600
10805
|
import { tmpdir as tmpdir5 } from "node:os";
|
|
@@ -10792,7 +10997,7 @@ import {
|
|
|
10792
10997
|
realpath as realpath5,
|
|
10793
10998
|
rename as rename3,
|
|
10794
10999
|
rm as rm7,
|
|
10795
|
-
stat as
|
|
11000
|
+
stat as stat7,
|
|
10796
11001
|
writeFile as writeFile5
|
|
10797
11002
|
} from "node:fs/promises";
|
|
10798
11003
|
import { createReadStream as createReadStream3, createWriteStream } from "node:fs";
|
|
@@ -11058,7 +11263,7 @@ function requireSuccess2(result, fallback) {
|
|
|
11058
11263
|
}
|
|
11059
11264
|
async function validateWorktree(input, timeoutMs, signal) {
|
|
11060
11265
|
const folder = await realpath5(input.folder);
|
|
11061
|
-
if (!(await
|
|
11266
|
+
if (!(await stat7(folder)).isDirectory())
|
|
11062
11267
|
throw new Error("Worktree is missing");
|
|
11063
11268
|
const gitDirectory2 = requireSuccess2(
|
|
11064
11269
|
await command(
|
|
@@ -11105,7 +11310,7 @@ async function validateSource(root, source) {
|
|
|
11105
11310
|
if (difference === ".." || difference.startsWith(`..${sep4}`) || isAbsolute4(difference)) {
|
|
11106
11311
|
throw new Error("Build source resolves outside the worktree");
|
|
11107
11312
|
}
|
|
11108
|
-
const information = await
|
|
11313
|
+
const information = await stat7(resolved);
|
|
11109
11314
|
if (source.kind === "PACKAGE" && !information.isFile()) {
|
|
11110
11315
|
throw new Error("Package.swift is missing");
|
|
11111
11316
|
}
|
|
@@ -11221,7 +11426,7 @@ async function workspaceProjectPaths(workspacePath2, folder) {
|
|
|
11221
11426
|
try {
|
|
11222
11427
|
const resolved = await realpath5(candidate);
|
|
11223
11428
|
const resolvedDifference = relative4(folder, resolved);
|
|
11224
|
-
if (resolvedDifference === ".." || resolvedDifference.startsWith(`..${sep4}`) || isAbsolute4(resolvedDifference) || !(await
|
|
11429
|
+
if (resolvedDifference === ".." || resolvedDifference.startsWith(`..${sep4}`) || isAbsolute4(resolvedDifference) || !(await stat7(resolved)).isDirectory()) {
|
|
11225
11430
|
continue;
|
|
11226
11431
|
}
|
|
11227
11432
|
projects.push(resolved);
|
|
@@ -11916,10 +12121,10 @@ function runLoggedCommand(options) {
|
|
|
11916
12121
|
let remainder = "";
|
|
11917
12122
|
const drain = (final = false) => {
|
|
11918
12123
|
while (remainder) {
|
|
11919
|
-
const
|
|
11920
|
-
if (
|
|
11921
|
-
let end =
|
|
11922
|
-
if (remainder[
|
|
12124
|
+
const delimiter2 = remainder.search(/[\r\n]/);
|
|
12125
|
+
if (delimiter2 < 0 && !final) return;
|
|
12126
|
+
let end = delimiter2 < 0 ? remainder.length : delimiter2 + 1;
|
|
12127
|
+
if (remainder[delimiter2] === "\r" && remainder[delimiter2 + 1] === "\n") {
|
|
11923
12128
|
end += 1;
|
|
11924
12129
|
}
|
|
11925
12130
|
const record = remainder.slice(0, end);
|
|
@@ -12272,14 +12477,14 @@ if (typeof hookModule.default === "function") {
|
|
|
12272
12477
|
}
|
|
12273
12478
|
async function pathExists(path) {
|
|
12274
12479
|
try {
|
|
12275
|
-
await
|
|
12480
|
+
await stat7(path);
|
|
12276
12481
|
return true;
|
|
12277
12482
|
} catch {
|
|
12278
12483
|
return false;
|
|
12279
12484
|
}
|
|
12280
12485
|
}
|
|
12281
12486
|
async function pathSize(path) {
|
|
12282
|
-
const information = await
|
|
12487
|
+
const information = await stat7(path);
|
|
12283
12488
|
if (information.isFile()) return information.size;
|
|
12284
12489
|
if (!information.isDirectory()) return 0;
|
|
12285
12490
|
let size = 0;
|
|
@@ -12291,7 +12496,7 @@ async function pathSize(path) {
|
|
|
12291
12496
|
}
|
|
12292
12497
|
async function fileChecksum(path) {
|
|
12293
12498
|
try {
|
|
12294
|
-
const information = await
|
|
12499
|
+
const information = await stat7(path);
|
|
12295
12500
|
if (!information.isFile()) return null;
|
|
12296
12501
|
const hash = createHash5("sha256");
|
|
12297
12502
|
await pipeline(createReadStream3(path), hash);
|
|
@@ -12875,10 +13080,10 @@ var runIosBuild = async (payload, timeoutMs, signal, onLog, context) => {
|
|
|
12875
13080
|
const testProductsPath = input.advancedSettings.priorTestProductsPath;
|
|
12876
13081
|
const xctestrunPath = input.advancedSettings.priorXctestrunPath;
|
|
12877
13082
|
if (testProductsPath) {
|
|
12878
|
-
if (!testProductsPath.endsWith(".xctestproducts") || !await pathExists(testProductsPath) || !(await
|
|
13083
|
+
if (!testProductsPath.endsWith(".xctestproducts") || !await pathExists(testProductsPath) || !(await stat7(testProductsPath)).isDirectory()) {
|
|
12879
13084
|
throw new Error("The captured test-products artifact is unavailable");
|
|
12880
13085
|
}
|
|
12881
|
-
} else if (!xctestrunPath?.endsWith(".xctestrun") || !await pathExists(xctestrunPath) || !(await
|
|
13086
|
+
} else if (!xctestrunPath?.endsWith(".xctestrun") || !await pathExists(xctestrunPath) || !(await stat7(xctestrunPath)).isFile()) {
|
|
12882
13087
|
throw new Error("The captured .xctestrun artifact is unavailable");
|
|
12883
13088
|
}
|
|
12884
13089
|
}
|
|
@@ -13176,7 +13381,7 @@ var downloadIosBuildArtifact = async (payload, timeoutMs, signal, onLog, context
|
|
|
13176
13381
|
if (!difference || difference === ".." || difference.startsWith(`..${sep4}`) || isAbsolute4(difference)) {
|
|
13177
13382
|
throw new Error("Build artifact resolves outside the build folder");
|
|
13178
13383
|
}
|
|
13179
|
-
const information = await
|
|
13384
|
+
const information = await stat7(target2);
|
|
13180
13385
|
let uploadPath = target2;
|
|
13181
13386
|
let filename = basename3(target2);
|
|
13182
13387
|
let contentType = "application/octet-stream";
|
|
@@ -13560,7 +13765,7 @@ var success = {
|
|
|
13560
13765
|
var runWorkflowTerminal = async (payloadValue, timeoutMs, signal, onLog, context) => {
|
|
13561
13766
|
const payload = parseWorkflowTerminalPayload(payloadValue);
|
|
13562
13767
|
const cwd = await realpath6(payload.cwd);
|
|
13563
|
-
const information = await
|
|
13768
|
+
const information = await stat8(cwd);
|
|
13564
13769
|
if (!information.isDirectory())
|
|
13565
13770
|
throw new Error("Workflow working directory is not a directory");
|
|
13566
13771
|
const directory = await mkdtemp5(join10(tmpdir5(), "aide-workflow-"));
|
|
@@ -13657,7 +13862,7 @@ var runWorkflowGitCheckpoint = async (payloadValue, _timeoutMs, signal) => {
|
|
|
13657
13862
|
|
|
13658
13863
|
// src/handlers/worktrees.ts
|
|
13659
13864
|
import { createWriteStream as createWriteStream2, watch } from "node:fs";
|
|
13660
|
-
import { mkdtemp as mkdtemp6, open as open2, readFile as readFile7, realpath as realpath7, rm as rm9, stat as
|
|
13865
|
+
import { mkdtemp as mkdtemp6, open as open2, readFile as readFile7, realpath as realpath7, rm as rm9, stat as stat9 } from "node:fs/promises";
|
|
13661
13866
|
import { tmpdir as tmpdir6 } from "node:os";
|
|
13662
13867
|
import { basename as basename4, dirname as dirname6, isAbsolute as isAbsolute5, join as join11, relative as relative5 } from "node:path";
|
|
13663
13868
|
import { spawn as spawn6 } from "node:child_process";
|
|
@@ -13714,7 +13919,7 @@ async function rebaseInProgress(folder, timeoutMs, signal) {
|
|
|
13714
13919
|
const candidate = pathResult.stdout.trim();
|
|
13715
13920
|
if (!candidate) continue;
|
|
13716
13921
|
try {
|
|
13717
|
-
await
|
|
13922
|
+
await stat9(isAbsolute5(candidate) ? candidate : join11(folder, candidate));
|
|
13718
13923
|
return true;
|
|
13719
13924
|
} catch {
|
|
13720
13925
|
}
|
|
@@ -13928,7 +14133,7 @@ async function origin(folder, timeoutMs, signal) {
|
|
|
13928
14133
|
}
|
|
13929
14134
|
async function validateWorktree2(input, timeoutMs, signal) {
|
|
13930
14135
|
const folder = await realpath7(input.folder);
|
|
13931
|
-
if (!(await
|
|
14136
|
+
if (!(await stat9(folder)).isDirectory())
|
|
13932
14137
|
throw new Error("Worktree is missing");
|
|
13933
14138
|
const observedGitDirectory = await gitDirectory(folder, timeoutMs, signal);
|
|
13934
14139
|
if (observedGitDirectory !== input.gitDirectory) {
|
|
@@ -14169,7 +14374,7 @@ function parseNumstat(value) {
|
|
|
14169
14374
|
}
|
|
14170
14375
|
async function untrackedLines(folder, path) {
|
|
14171
14376
|
try {
|
|
14172
|
-
const file = await
|
|
14377
|
+
const file = await stat9(`${folder}/${path}`);
|
|
14173
14378
|
if (!file.isFile() || file.size > 1024 * 1024) return null;
|
|
14174
14379
|
const contents = await readFile7(`${folder}/${path}`);
|
|
14175
14380
|
if (contents.includes(0)) return null;
|
|
@@ -14465,7 +14670,7 @@ async function availableSide(side, folder, timeoutMs, signal) {
|
|
|
14465
14670
|
try {
|
|
14466
14671
|
const resolved = await realpath7(side.path);
|
|
14467
14672
|
const difference = relative5(folder, resolved);
|
|
14468
|
-
return difference !== ".." && !difference.startsWith("../") && (await
|
|
14673
|
+
return difference !== ".." && !difference.startsWith("../") && (await stat9(resolved)).isFile();
|
|
14469
14674
|
} catch {
|
|
14470
14675
|
return false;
|
|
14471
14676
|
}
|
|
@@ -14734,7 +14939,7 @@ var downloadWorktreeDiffAsset = async (payload, timeoutMs, signal, _onLog, conte
|
|
|
14734
14939
|
signal
|
|
14735
14940
|
);
|
|
14736
14941
|
}
|
|
14737
|
-
const information = await
|
|
14942
|
+
const information = await stat9(uploadPath);
|
|
14738
14943
|
if (!information.isFile() || information.size > 20 * 1024 * 1024) {
|
|
14739
14944
|
throw new Error("Diff image exceeds the 20 MiB limit");
|
|
14740
14945
|
}
|
|
@@ -14925,7 +15130,7 @@ async function chooseNewBranch(folder, candidates, allowedCurrentBranch, timeout
|
|
|
14925
15130
|
}
|
|
14926
15131
|
async function validateBranchRoot(input, timeoutMs, signal) {
|
|
14927
15132
|
const rootFolder = await realpath7(input.rootFolder);
|
|
14928
|
-
if (!(await
|
|
15133
|
+
if (!(await stat9(rootFolder)).isDirectory()) {
|
|
14929
15134
|
throw new Error("Base repository is missing");
|
|
14930
15135
|
}
|
|
14931
15136
|
if (await origin(rootFolder, timeoutMs, signal) !== input.expectedOrigin) {
|
|
@@ -14994,7 +15199,7 @@ var branchWorktree = async (payload, timeoutMs, signal) => {
|
|
|
14994
15199
|
) : changeFolder;
|
|
14995
15200
|
if (input.action === "CREATE") {
|
|
14996
15201
|
try {
|
|
14997
|
-
await
|
|
15202
|
+
await stat9(targetFolder);
|
|
14998
15203
|
throw new Error(`Worktree folder already exists: ${targetFolder}`);
|
|
14999
15204
|
} catch (error) {
|
|
15000
15205
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
@@ -15233,7 +15438,7 @@ var checkoutMovedWorktree = async (payload, timeoutMs, signal) => {
|
|
|
15233
15438
|
`${basename4(rootFolder)}-${input.branch.replaceAll("/", "-")}`
|
|
15234
15439
|
);
|
|
15235
15440
|
try {
|
|
15236
|
-
await
|
|
15441
|
+
await stat9(targetFolder);
|
|
15237
15442
|
throw new Error(`Worktree folder already exists: ${targetFolder}`);
|
|
15238
15443
|
} catch (error) {
|
|
15239
15444
|
if (!(error instanceof Error) || !("code" in error) || error.code !== "ENOENT") {
|
|
@@ -15394,7 +15599,7 @@ var checkoutMovedWorktree = async (payload, timeoutMs, signal) => {
|
|
|
15394
15599
|
var deleteWorktree = async (payload, timeoutMs, signal) => {
|
|
15395
15600
|
const input = worktreeDeleteJobPayload(payload);
|
|
15396
15601
|
const rootFolder = await realpath7(input.rootFolder);
|
|
15397
|
-
if (!(await
|
|
15602
|
+
if (!(await stat9(rootFolder)).isDirectory()) {
|
|
15398
15603
|
throw new Error("Base repository is missing");
|
|
15399
15604
|
}
|
|
15400
15605
|
if (await origin(rootFolder, timeoutMs, signal) !== input.expectedOrigin) {
|
|
@@ -15942,7 +16147,7 @@ var CodebaseMonitor = class {
|
|
|
15942
16147
|
// src/runs/run-manager.ts
|
|
15943
16148
|
import { execFile as execFile4 } from "node:child_process";
|
|
15944
16149
|
import { mkdir as mkdir6, rm as rm13 } from "node:fs/promises";
|
|
15945
|
-
import { dirname as dirname8, join as
|
|
16150
|
+
import { dirname as dirname8, join as join16 } from "node:path";
|
|
15946
16151
|
import { promisify as promisify4 } from "node:util";
|
|
15947
16152
|
|
|
15948
16153
|
// src/runs/journal.ts
|
|
@@ -16095,6 +16300,9 @@ var RunJournal = class {
|
|
|
16095
16300
|
|
|
16096
16301
|
// src/runs/claude-adapter.ts
|
|
16097
16302
|
import { randomUUID as randomUUID5 } from "node:crypto";
|
|
16303
|
+
import { accessSync, constants } from "node:fs";
|
|
16304
|
+
import { homedir as homedir8 } from "node:os";
|
|
16305
|
+
import { delimiter, join as join14 } from "node:path";
|
|
16098
16306
|
|
|
16099
16307
|
// ../../node_modules/@anthropic-ai/claude-agent-sdk/sdk.mjs
|
|
16100
16308
|
import { createRequire as RV } from "node:module";
|
|
@@ -41902,6 +42110,28 @@ function answerArrays(value) {
|
|
|
41902
42110
|
}
|
|
41903
42111
|
|
|
41904
42112
|
// src/runs/claude-adapter.ts
|
|
42113
|
+
function isExecutable(path) {
|
|
42114
|
+
try {
|
|
42115
|
+
accessSync(path, constants.X_OK);
|
|
42116
|
+
return true;
|
|
42117
|
+
} catch {
|
|
42118
|
+
return false;
|
|
42119
|
+
}
|
|
42120
|
+
}
|
|
42121
|
+
function findClaudeCodeExecutable(options = {}) {
|
|
42122
|
+
const env = options.env ?? process.env;
|
|
42123
|
+
const home = options.home ?? homedir8();
|
|
42124
|
+
const platform = options.platform ?? process.platform;
|
|
42125
|
+
const executable = platform === "win32" ? "claude.exe" : "claude";
|
|
42126
|
+
const candidates = [
|
|
42127
|
+
env.CONTROL_AGENT_CLAUDE_EXECUTABLE?.trim(),
|
|
42128
|
+
...(env.PATH ?? "").split(delimiter).filter(Boolean).map((directory) => join14(directory, executable)),
|
|
42129
|
+
join14(home, ".local", "bin", executable),
|
|
42130
|
+
...platform === "darwin" ? ["/opt/homebrew/bin/claude", "/usr/local/bin/claude"] : []
|
|
42131
|
+
].filter((candidate) => Boolean(candidate));
|
|
42132
|
+
const canExecute = options.isExecutable ?? isExecutable;
|
|
42133
|
+
return [...new Set(candidates)].find(canExecute);
|
|
42134
|
+
}
|
|
41905
42135
|
var MessageQueue = class {
|
|
41906
42136
|
values = [];
|
|
41907
42137
|
waiters = [];
|
|
@@ -42035,9 +42265,11 @@ var ClaudeAdapter = class {
|
|
|
42035
42265
|
catalog() {
|
|
42036
42266
|
this.catalogPromise ??= (async () => {
|
|
42037
42267
|
const messages = new MessageQueue();
|
|
42268
|
+
const pathToClaudeCodeExecutable = findClaudeCodeExecutable();
|
|
42038
42269
|
const instance = uAt({
|
|
42039
42270
|
prompt: messages,
|
|
42040
42271
|
options: {
|
|
42272
|
+
...pathToClaudeCodeExecutable ? { pathToClaudeCodeExecutable } : {},
|
|
42041
42273
|
env: claudeEnvironment(),
|
|
42042
42274
|
permissionMode: "plan"
|
|
42043
42275
|
}
|
|
@@ -42071,9 +42303,11 @@ var ClaudeAdapter = class {
|
|
|
42071
42303
|
const effort = ["low", "medium", "high", "xhigh", "max"].includes(
|
|
42072
42304
|
input.run.effort ?? ""
|
|
42073
42305
|
) ? input.run.effort : void 0;
|
|
42306
|
+
const pathToClaudeCodeExecutable = findClaudeCodeExecutable();
|
|
42074
42307
|
activeQuery = uAt({
|
|
42075
42308
|
prompt: messages,
|
|
42076
42309
|
options: {
|
|
42310
|
+
...pathToClaudeCodeExecutable ? { pathToClaudeCodeExecutable } : {},
|
|
42077
42311
|
cwd: input.run.worktree.folder,
|
|
42078
42312
|
...input.run.model !== "default" ? { model: input.run.model } : {},
|
|
42079
42313
|
...effort ? { effort } : {},
|
|
@@ -42236,7 +42470,7 @@ import {
|
|
|
42236
42470
|
} from "node:child_process";
|
|
42237
42471
|
import { mkdtemp as mkdtemp7, rm as rm12, writeFile as writeFile8 } from "node:fs/promises";
|
|
42238
42472
|
import { tmpdir as tmpdir7 } from "node:os";
|
|
42239
|
-
import { join as
|
|
42473
|
+
import { join as join15 } from "node:path";
|
|
42240
42474
|
import { createInterface } from "node:readline";
|
|
42241
42475
|
import { promisify as promisify3 } from "node:util";
|
|
42242
42476
|
var SUPPORTED_CODEX_APP_SERVER_MINORS = ["0.144", "0.145"];
|
|
@@ -42363,7 +42597,7 @@ var CodexAppServer = class {
|
|
|
42363
42597
|
}
|
|
42364
42598
|
}
|
|
42365
42599
|
async createBundledModelCatalog() {
|
|
42366
|
-
const directory = await mkdtemp7(
|
|
42600
|
+
const directory = await mkdtemp7(join15(tmpdir7(), "aide-codex-models-"));
|
|
42367
42601
|
try {
|
|
42368
42602
|
const { stdout } = await execFileAsync2(
|
|
42369
42603
|
"codex",
|
|
@@ -42373,7 +42607,7 @@ var CodexAppServer = class {
|
|
|
42373
42607
|
maxBuffer: 16 * 1024 * 1024
|
|
42374
42608
|
}
|
|
42375
42609
|
);
|
|
42376
|
-
const catalogPath =
|
|
42610
|
+
const catalogPath = join15(directory, "models.json");
|
|
42377
42611
|
await writeFile8(catalogPath, stdout, "utf8");
|
|
42378
42612
|
this.modelCatalogDirectory = directory;
|
|
42379
42613
|
return catalogPath;
|
|
@@ -49067,7 +49301,7 @@ var RunManager = class {
|
|
|
49067
49301
|
5
|
|
49068
49302
|
);
|
|
49069
49303
|
await this.completeCommand(command3.id, "SUCCEEDED");
|
|
49070
|
-
await rm13(
|
|
49304
|
+
await rm13(join16(dirname8(configPath()), "runs", run.id, "attachments"), {
|
|
49071
49305
|
recursive: true,
|
|
49072
49306
|
force: true
|
|
49073
49307
|
}).catch(() => void 0);
|
|
@@ -49248,7 +49482,7 @@ var RunManager = class {
|
|
|
49248
49482
|
this.active.delete(run.id);
|
|
49249
49483
|
this.interruptionRequests.delete(run.id);
|
|
49250
49484
|
this.executingCommands.delete(command3.id);
|
|
49251
|
-
await rm13(
|
|
49485
|
+
await rm13(join16(dirname8(configPath()), "runs", run.id, "attachments"), {
|
|
49252
49486
|
recursive: true,
|
|
49253
49487
|
force: true
|
|
49254
49488
|
}).catch(() => void 0);
|
|
@@ -49476,11 +49710,11 @@ var RunManager = class {
|
|
|
49476
49710
|
}
|
|
49477
49711
|
async stageAttachments(runId, attachments) {
|
|
49478
49712
|
if (!attachments.length) return [];
|
|
49479
|
-
const directory =
|
|
49713
|
+
const directory = join16(dirname8(configPath()), "runs", runId, "attachments");
|
|
49480
49714
|
await mkdir6(directory, { recursive: true, mode: 448 });
|
|
49481
49715
|
return Promise.all(
|
|
49482
49716
|
attachments.map(async (attachment) => {
|
|
49483
|
-
const path =
|
|
49717
|
+
const path = join16(
|
|
49484
49718
|
directory,
|
|
49485
49719
|
`${attachment.id}-${safeFilename(attachment.filename)}`
|
|
49486
49720
|
);
|
|
@@ -49596,6 +49830,10 @@ var RunManager = class {
|
|
|
49596
49830
|
}
|
|
49597
49831
|
};
|
|
49598
49832
|
|
|
49833
|
+
// ../agent-contract/src/disk-space.ts
|
|
49834
|
+
var DISK_SPACE_POLL_INTERVAL_SECONDS = 60;
|
|
49835
|
+
var DISK_SPACE_STALE_AFTER_SECONDS = DISK_SPACE_POLL_INTERVAL_SECONDS * 2;
|
|
49836
|
+
|
|
49599
49837
|
// src/agent-runtime.ts
|
|
49600
49838
|
function configuredIntervalMs(value, fallbackSeconds, minSeconds, maxSeconds) {
|
|
49601
49839
|
return (Number.isInteger(value) && value >= minSeconds && value <= maxSeconds ? value : fallbackSeconds) * 1e3;
|
|
@@ -49618,6 +49856,9 @@ async function runAgent(config, signal) {
|
|
|
49618
49856
|
let heartbeatTimer;
|
|
49619
49857
|
let jobReconciliationTimer;
|
|
49620
49858
|
let codebaseTimer;
|
|
49859
|
+
let diskSpaceTimer;
|
|
49860
|
+
let diskSpaceRunning = false;
|
|
49861
|
+
let diskSpaceIntervalMs = DISK_SPACE_POLL_INTERVAL_SECONDS * 1e3;
|
|
49621
49862
|
let startupRecoveryPending = true;
|
|
49622
49863
|
const interruptedJobs = /* @__PURE__ */ new Set();
|
|
49623
49864
|
const reconcileJobs = async (recoverInterrupted) => {
|
|
@@ -49771,11 +50012,48 @@ async function runAgent(config, signal) {
|
|
|
49771
50012
|
codebaseTimer = void 0;
|
|
49772
50013
|
void reconcileCodebases();
|
|
49773
50014
|
};
|
|
50015
|
+
const scheduleDiskSpacePoll = () => {
|
|
50016
|
+
if (diskSpaceTimer) clearTimeout(diskSpaceTimer);
|
|
50017
|
+
if (!signal.aborted) {
|
|
50018
|
+
diskSpaceTimer = setTimeout(
|
|
50019
|
+
() => void runDiskSpacePoll(),
|
|
50020
|
+
diskSpaceIntervalMs
|
|
50021
|
+
);
|
|
50022
|
+
}
|
|
50023
|
+
};
|
|
50024
|
+
const runDiskSpacePoll = async () => {
|
|
50025
|
+
if (diskSpaceRunning || signal.aborted) return;
|
|
50026
|
+
diskSpaceRunning = true;
|
|
50027
|
+
if (diskSpaceTimer) clearTimeout(diskSpaceTimer);
|
|
50028
|
+
diskSpaceTimer = void 0;
|
|
50029
|
+
try {
|
|
50030
|
+
const configuration = await client2.diskSpaceConfiguration();
|
|
50031
|
+
diskSpaceIntervalMs = Math.max(
|
|
50032
|
+
1e3,
|
|
50033
|
+
configuration.pollIntervalSeconds * 1e3
|
|
50034
|
+
);
|
|
50035
|
+
if (configuration.enabled) {
|
|
50036
|
+
const report = await collectAgentDiskSpace(configuration, signal);
|
|
50037
|
+
await client2.reportDiskSpace(report);
|
|
50038
|
+
}
|
|
50039
|
+
} catch (error) {
|
|
50040
|
+
if (!signal.aborted) {
|
|
50041
|
+
console.error(
|
|
50042
|
+
"Disk space poll failed:",
|
|
50043
|
+
error instanceof Error ? error.message : error
|
|
50044
|
+
);
|
|
50045
|
+
}
|
|
50046
|
+
} finally {
|
|
50047
|
+
diskSpaceRunning = false;
|
|
50048
|
+
scheduleDiskSpacePoll();
|
|
50049
|
+
}
|
|
50050
|
+
};
|
|
49774
50051
|
await refreshCadence();
|
|
49775
50052
|
await heartbeat();
|
|
49776
50053
|
await runJobReconciliation();
|
|
49777
50054
|
await runManager.start();
|
|
49778
50055
|
void reconcileCodebases();
|
|
50056
|
+
void runDiskSpacePoll();
|
|
49779
50057
|
const subscriptionClient = createAgentSubscriptionClient(config);
|
|
49780
50058
|
const unsubscribe = subscribeToAgentEvents(
|
|
49781
50059
|
subscriptionClient,
|
|
@@ -49788,11 +50066,14 @@ async function runAgent(config, signal) {
|
|
|
49788
50066
|
requestCodebaseReconcile();
|
|
49789
50067
|
} else if (event.type === "RUN_COMMAND_AVAILABLE") {
|
|
49790
50068
|
runManager.execute(event.runCommand);
|
|
50069
|
+
} else if (event.type === "DISK_SPACE_POLL_REQUESTED") {
|
|
50070
|
+
void runDiskSpacePoll();
|
|
49791
50071
|
} else {
|
|
49792
50072
|
void refreshCadence().then(() => {
|
|
49793
50073
|
scheduleHeartbeat();
|
|
49794
50074
|
scheduleJobReconciliation();
|
|
49795
50075
|
requestCodebaseReconcile();
|
|
50076
|
+
void runDiskSpacePoll();
|
|
49796
50077
|
});
|
|
49797
50078
|
}
|
|
49798
50079
|
}
|
|
@@ -49804,6 +50085,7 @@ async function runAgent(config, signal) {
|
|
|
49804
50085
|
if (heartbeatTimer) clearTimeout(heartbeatTimer);
|
|
49805
50086
|
if (jobReconciliationTimer) clearTimeout(jobReconciliationTimer);
|
|
49806
50087
|
if (codebaseTimer) clearTimeout(codebaseTimer);
|
|
50088
|
+
if (diskSpaceTimer) clearTimeout(diskSpaceTimer);
|
|
49807
50089
|
unsubscribe();
|
|
49808
50090
|
await subscriptionClient.dispose();
|
|
49809
50091
|
await executor.cancelAll();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ai-development-environment/control-agent",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.56",
|
|
4
4
|
"description": "Control agent for the AI Development Environment",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"ws": "8.21.1"
|
|
29
29
|
},
|
|
30
30
|
"scripts": {
|
|
31
|
-
"build": "
|
|
31
|
+
"build": "node esbuild.config.mjs",
|
|
32
|
+
"smoke": "node dist/control-agent.js --help",
|
|
32
33
|
"prepublishOnly": "npm run build",
|
|
33
34
|
"dev": "node --watch --watch-preserve-output --import tsx src/index.ts dev",
|
|
34
35
|
"format": "prettier --write --ignore-path ../../.gitignore --ignore-path ../../.prettierignore .",
|
|
@@ -38,8 +39,8 @@
|
|
|
38
39
|
"type-check": "tsc --noEmit -p tsconfig.json",
|
|
39
40
|
"test": "vitest",
|
|
40
41
|
"test:run": "vitest run",
|
|
41
|
-
"full-check": "npm run format && npm run lint:fix && npm run type-check && npm run test:run && npm run build",
|
|
42
|
-
"full-check:ci": "npm run format:check && npm run lint && npm run type-check && npm run test:run && npm run build",
|
|
42
|
+
"full-check": "npm run format && npm run lint:fix && npm run type-check && npm run test:run && npm run build && npm run smoke",
|
|
43
|
+
"full-check:ci": "npm run format:check && npm run lint && npm run type-check && npm run test:run && npm run build && npm run smoke",
|
|
43
44
|
"full-check:dev": "npm run full-check && npm run dev",
|
|
44
45
|
"upgrade": "ncu -u --cooldown 48h && npm install",
|
|
45
46
|
"upgrade:check": "ncu --cooldown 48h"
|