@ai-development-environment/control-agent 0.0.134 → 0.0.136
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 +343 -23
- package/package.json +1 -1
package/dist/control-agent.js
CHANGED
|
@@ -6752,6 +6752,14 @@ var AgentGraphQLClient = class {
|
|
|
6752
6752
|
{ jobId, attemptId, chunks }
|
|
6753
6753
|
);
|
|
6754
6754
|
}
|
|
6755
|
+
reportBuildDeploymentLaunched(jobId, deploymentId, launchedAt) {
|
|
6756
|
+
return this.request(
|
|
6757
|
+
`mutation ReportBuildDeploymentLaunched($jobId: ID!, $deploymentId: ID!, $launchedAt: String!) {
|
|
6758
|
+
reportBuildDeploymentLaunched(jobId: $jobId, deploymentId: $deploymentId, launchedAt: $launchedAt)
|
|
6759
|
+
}`,
|
|
6760
|
+
{ jobId, deploymentId, launchedAt }
|
|
6761
|
+
);
|
|
6762
|
+
}
|
|
6755
6763
|
reportBuildProgress(input) {
|
|
6756
6764
|
return this.request(
|
|
6757
6765
|
`mutation ReportBuildProgress($input: BuildProgressInput!) {
|
|
@@ -8133,6 +8141,7 @@ var WORKTREE_INSPECT_JOB_KIND = "worktree.inspect";
|
|
|
8133
8141
|
var WORKTREE_OPERATION_JOB_KIND = "worktree.operation";
|
|
8134
8142
|
var WORKTREE_COMMIT_JOB_KIND = "worktree.commit";
|
|
8135
8143
|
var WORKTREE_AUTO_SYNC_JOB_KIND = "worktree.auto-sync";
|
|
8144
|
+
var WORKTREE_REVIEWED_SYNC_CAPABILITY = "worktree.auto-sync.reviewed-head";
|
|
8136
8145
|
var WORKTREE_PREPARATION_JOB_KIND = "worktree.prepare";
|
|
8137
8146
|
var WORKTREE_GIT_INSPECT_JOB_KIND = "worktree.git.inspect";
|
|
8138
8147
|
var WORKTREE_GIT_OPERATION_JOB_KIND = "worktree.git.operation";
|
|
@@ -8142,6 +8151,7 @@ var JIRA_BRANCH_GENERATE_JOB_KIND = "jira.branch.generate";
|
|
|
8142
8151
|
var WORKTREE_MOVE_PUSH_JOB_KIND = "worktree.move.push";
|
|
8143
8152
|
var WORKTREE_MOVE_CHECKOUT_JOB_KIND = "worktree.move.checkout";
|
|
8144
8153
|
var WORKTREE_DELETE_JOB_KIND = "worktree.delete";
|
|
8154
|
+
var WORKTREE_DELETE_BUILD_DATA_CAPABILITY = "worktree.delete.xcode-cleanup";
|
|
8145
8155
|
var WORKTREE_DIFF_JOB_KIND = "worktree.diff.inspect";
|
|
8146
8156
|
var WORKTREE_DIFF_ASSET_JOB_KIND = "worktree.diff.asset";
|
|
8147
8157
|
var WORKTREE_JOB_KINDS = [
|
|
@@ -8560,6 +8570,7 @@ function worktreeMoveCheckoutJobPayload(value) {
|
|
|
8560
8570
|
function worktreeDeleteJobPayload(value) {
|
|
8561
8571
|
const payload = objectValue4(value, "worktree delete payload");
|
|
8562
8572
|
const allowed = /* @__PURE__ */ new Set([
|
|
8573
|
+
"derivedData",
|
|
8563
8574
|
"moveId",
|
|
8564
8575
|
"codebaseId",
|
|
8565
8576
|
"rootFolder",
|
|
@@ -8593,7 +8604,20 @@ function worktreeDeleteJobPayload(value) {
|
|
|
8593
8604
|
if (payload.requireClean && !expectedHeadSha) {
|
|
8594
8605
|
throw new Error("Clean worktree deletion requires an expected HEAD");
|
|
8595
8606
|
}
|
|
8607
|
+
const derivedData = payload.derivedData === void 0 ? { mode: "DEFAULT", path: null } : objectValue4(payload.derivedData, "worktree delete payload.derivedData");
|
|
8608
|
+
const unexpectedDerivedData = Object.keys(derivedData).find(
|
|
8609
|
+
(key) => !["mode", "path"].includes(key)
|
|
8610
|
+
);
|
|
8611
|
+
if (unexpectedDerivedData)
|
|
8612
|
+
throw new Error(`Unexpected derived data field: ${unexpectedDerivedData}`);
|
|
8596
8613
|
return {
|
|
8614
|
+
derivedData: {
|
|
8615
|
+
mode: parseDerivedDataLocationMode(derivedData.mode),
|
|
8616
|
+
path: nullableString3(
|
|
8617
|
+
derivedData.path,
|
|
8618
|
+
"worktree delete payload.derivedData.path"
|
|
8619
|
+
)
|
|
8620
|
+
},
|
|
8597
8621
|
moveId: nullableString3(payload.moveId, "worktree delete payload.moveId"),
|
|
8598
8622
|
codebaseId: stringValue4(
|
|
8599
8623
|
payload.codebaseId,
|
|
@@ -8749,7 +8773,8 @@ function worktreeAutoSyncJobPayload(value) {
|
|
|
8749
8773
|
"baseBranch",
|
|
8750
8774
|
"phase",
|
|
8751
8775
|
"forcePreparations",
|
|
8752
|
-
"preparations"
|
|
8776
|
+
"preparations",
|
|
8777
|
+
"mergeGuard"
|
|
8753
8778
|
]);
|
|
8754
8779
|
const unexpected = Object.keys(payload).find((key) => !allowed.has(key));
|
|
8755
8780
|
if (unexpected) {
|
|
@@ -8765,6 +8790,27 @@ function worktreeAutoSyncJobPayload(value) {
|
|
|
8765
8790
|
"worktree auto sync payload.forcePreparations must be a boolean"
|
|
8766
8791
|
);
|
|
8767
8792
|
}
|
|
8793
|
+
let mergeGuard;
|
|
8794
|
+
if (payload.mergeGuard !== void 0) {
|
|
8795
|
+
const guard = objectValue4(payload.mergeGuard, "merge sync guard");
|
|
8796
|
+
mergeGuard = {
|
|
8797
|
+
expectedHeadSha: stringValue4(
|
|
8798
|
+
guard.expectedHeadSha,
|
|
8799
|
+
"merge sync expected head"
|
|
8800
|
+
),
|
|
8801
|
+
targetUrl: stringValue4(guard.targetUrl, "merge sync target URL"),
|
|
8802
|
+
targetBranch: stringValue4(guard.targetBranch, "merge sync target branch"),
|
|
8803
|
+
targetSha: stringValue4(guard.targetSha, "merge sync target SHA")
|
|
8804
|
+
};
|
|
8805
|
+
if (!/^[a-f0-9]{40,64}$/i.test(mergeGuard.expectedHeadSha))
|
|
8806
|
+
throw new Error("Invalid merge sync source SHA");
|
|
8807
|
+
if (!/^[a-f0-9]{40,64}$/i.test(mergeGuard.targetSha))
|
|
8808
|
+
throw new Error("Invalid merge sync target SHA");
|
|
8809
|
+
if (!validGitBranchName(mergeGuard.targetBranch))
|
|
8810
|
+
throw new Error("Invalid merge sync target branch");
|
|
8811
|
+
if (payload.phase !== "SYNC")
|
|
8812
|
+
throw new Error("Reviewed sync requires the SYNC phase");
|
|
8813
|
+
}
|
|
8768
8814
|
return {
|
|
8769
8815
|
codebaseId: stringValue4(
|
|
8770
8816
|
payload.codebaseId,
|
|
@@ -8788,6 +8834,7 @@ function worktreeAutoSyncJobPayload(value) {
|
|
|
8788
8834
|
"worktree auto sync payload.baseBranch"
|
|
8789
8835
|
),
|
|
8790
8836
|
phase: payload.phase,
|
|
8837
|
+
...mergeGuard ? { mergeGuard } : {},
|
|
8791
8838
|
forcePreparations: payload.forcePreparations === true,
|
|
8792
8839
|
preparations: preparationDefinitions(
|
|
8793
8840
|
payload.preparations ?? [],
|
|
@@ -11152,7 +11199,7 @@ function tailscaleServeRemovePayload(value) {
|
|
|
11152
11199
|
// package.json
|
|
11153
11200
|
var package_default = {
|
|
11154
11201
|
name: "@ai-development-environment/control-agent",
|
|
11155
|
-
version: "0.0.
|
|
11202
|
+
version: "0.0.136",
|
|
11156
11203
|
description: "Control agent for the AI Development Environment",
|
|
11157
11204
|
license: "MIT",
|
|
11158
11205
|
repository: {
|
|
@@ -11223,6 +11270,7 @@ var PORTABLE_AGENT_CAPABILITIES = [
|
|
|
11223
11270
|
...CODEBASE_JOB_KINDS,
|
|
11224
11271
|
CODEBASE_RECONCILE_EVENT_CAPABILITY,
|
|
11225
11272
|
...WORKTREE_JOB_KINDS,
|
|
11273
|
+
WORKTREE_REVIEWED_SYNC_CAPABILITY,
|
|
11226
11274
|
...SKILL_JOB_KINDS,
|
|
11227
11275
|
...COVERAGE_JOB_KINDS,
|
|
11228
11276
|
"runs.protocol.v1",
|
|
@@ -11233,6 +11281,7 @@ var PORTABLE_AGENT_CAPABILITIES = [
|
|
|
11233
11281
|
...WORKFLOW_JOB_KINDS
|
|
11234
11282
|
];
|
|
11235
11283
|
var MACOS_AGENT_CAPABILITIES = [
|
|
11284
|
+
WORKTREE_DELETE_BUILD_DATA_CAPABILITY,
|
|
11236
11285
|
...BUILD_DATA_JOB_KINDS,
|
|
11237
11286
|
...IOS_BUILD_JOB_KINDS,
|
|
11238
11287
|
...SIGNING_ASSET_JOB_KINDS,
|
|
@@ -47672,6 +47721,7 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
|
|
|
47672
47721
|
const logPath = join12(directory, "deployment.log");
|
|
47673
47722
|
const started = Date.now();
|
|
47674
47723
|
let failure = null;
|
|
47724
|
+
let launchedAt = null;
|
|
47675
47725
|
try {
|
|
47676
47726
|
if (deployment.destination.type === "SIMULATOR") {
|
|
47677
47727
|
if (deployment.destination.state !== "Booted") {
|
|
@@ -47719,7 +47769,9 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
|
|
|
47719
47769
|
logPath
|
|
47720
47770
|
});
|
|
47721
47771
|
if (bootStatus.exitCode !== 0)
|
|
47722
|
-
failure = cleanError2(
|
|
47772
|
+
failure = cleanError2(
|
|
47773
|
+
bootStatus.output || "Simulator did not finish booting"
|
|
47774
|
+
);
|
|
47723
47775
|
}
|
|
47724
47776
|
if (!failure) {
|
|
47725
47777
|
const install = await runSimpleLogged(logger, {
|
|
@@ -47731,7 +47783,10 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
|
|
|
47731
47783
|
scopeId: deployment.id,
|
|
47732
47784
|
logPath
|
|
47733
47785
|
});
|
|
47734
|
-
if (install.exitCode !== 0)
|
|
47786
|
+
if (install.exitCode !== 0)
|
|
47787
|
+
failure = cleanError2(
|
|
47788
|
+
install.output || "Could not install the app"
|
|
47789
|
+
);
|
|
47735
47790
|
}
|
|
47736
47791
|
if (!failure) {
|
|
47737
47792
|
const launch = await runSimpleLogged(logger, {
|
|
@@ -47748,7 +47803,9 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
|
|
|
47748
47803
|
scopeId: deployment.id,
|
|
47749
47804
|
logPath
|
|
47750
47805
|
});
|
|
47751
|
-
if (launch.exitCode !== 0)
|
|
47806
|
+
if (launch.exitCode !== 0)
|
|
47807
|
+
failure = cleanError2(launch.output || "Could not launch the app");
|
|
47808
|
+
else launchedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
47752
47809
|
}
|
|
47753
47810
|
} else {
|
|
47754
47811
|
const verify = await runLoggedCommand({
|
|
@@ -47784,7 +47841,10 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
|
|
|
47784
47841
|
scopeId: deployment.id,
|
|
47785
47842
|
logPath
|
|
47786
47843
|
});
|
|
47787
|
-
if (install.exitCode !== 0)
|
|
47844
|
+
if (install.exitCode !== 0)
|
|
47845
|
+
failure = cleanError2(
|
|
47846
|
+
install.output || "Could not install the app"
|
|
47847
|
+
);
|
|
47788
47848
|
}
|
|
47789
47849
|
if (!failure) {
|
|
47790
47850
|
const launch = await runSimpleLogged(logger, {
|
|
@@ -47805,7 +47865,9 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
|
|
|
47805
47865
|
scopeId: deployment.id,
|
|
47806
47866
|
logPath
|
|
47807
47867
|
});
|
|
47808
|
-
if (launch.exitCode !== 0)
|
|
47868
|
+
if (launch.exitCode !== 0)
|
|
47869
|
+
failure = cleanError2(launch.output || "Could not launch the app");
|
|
47870
|
+
else launchedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
47809
47871
|
}
|
|
47810
47872
|
}
|
|
47811
47873
|
} catch (deploymentError) {
|
|
@@ -47818,10 +47880,27 @@ async function deployPreparedIosBuild(input, folder, appPath, timeoutMs, signal2
|
|
|
47818
47880
|
deployment.id
|
|
47819
47881
|
);
|
|
47820
47882
|
}
|
|
47883
|
+
if (launchedAt && context?.reportBuildDeploymentLaunched) {
|
|
47884
|
+
try {
|
|
47885
|
+
await context.reportBuildDeploymentLaunched(
|
|
47886
|
+
deployment.id,
|
|
47887
|
+
launchedAt
|
|
47888
|
+
);
|
|
47889
|
+
} catch (error) {
|
|
47890
|
+
logger.emit(
|
|
47891
|
+
"LAUNCH",
|
|
47892
|
+
"SYSTEM",
|
|
47893
|
+
`Launch reporting will be retried on completion: ${cleanError2(error)}`,
|
|
47894
|
+
"DEPLOYMENT",
|
|
47895
|
+
deployment.id
|
|
47896
|
+
);
|
|
47897
|
+
}
|
|
47898
|
+
}
|
|
47821
47899
|
outcomes.push({
|
|
47822
47900
|
id: deployment.id,
|
|
47823
47901
|
status: signal2.aborted ? "CANCELLED" : failure ? "FAILED" : "SUCCEEDED",
|
|
47824
47902
|
error: failure,
|
|
47903
|
+
launchedAt,
|
|
47825
47904
|
durationMs: Date.now() - started,
|
|
47826
47905
|
outputRelativePath: relative4(input.artifactDirectory, logPath)
|
|
47827
47906
|
});
|
|
@@ -49226,7 +49305,14 @@ import {
|
|
|
49226
49305
|
statfs
|
|
49227
49306
|
} from "node:fs/promises";
|
|
49228
49307
|
import { homedir as homedir12 } from "node:os";
|
|
49229
|
-
import {
|
|
49308
|
+
import {
|
|
49309
|
+
basename as basename4,
|
|
49310
|
+
dirname as dirname8,
|
|
49311
|
+
isAbsolute as isAbsolute6,
|
|
49312
|
+
join as join16,
|
|
49313
|
+
relative as relative7,
|
|
49314
|
+
resolve as resolve7
|
|
49315
|
+
} from "node:path";
|
|
49230
49316
|
var successfulProcess7 = {
|
|
49231
49317
|
exitCode: 0,
|
|
49232
49318
|
signal: null,
|
|
@@ -49388,6 +49474,53 @@ var scanBuildData = async (rawPayload, timeoutMs, signal2) => {
|
|
|
49388
49474
|
if (deviceSupport.warning) warnings.push(deviceSupport.warning);
|
|
49389
49475
|
return { ...successfulProcess7, entries, warnings };
|
|
49390
49476
|
};
|
|
49477
|
+
async function ownedWorktreeBuildData(folder, configuration, timeoutMs, signal2) {
|
|
49478
|
+
const within = (parent, child) => {
|
|
49479
|
+
const path = relative7(parent, child);
|
|
49480
|
+
return path === "" || !path.startsWith(`..${process.platform === "win32" ? "\\" : "/"}`) && path !== ".." && !isAbsolute6(path);
|
|
49481
|
+
};
|
|
49482
|
+
const roots = await configuredRoots({
|
|
49483
|
+
...configuration,
|
|
49484
|
+
worktrees: [{ id: "deleted-worktree", folder }]
|
|
49485
|
+
});
|
|
49486
|
+
const targets = [];
|
|
49487
|
+
const warnings = [];
|
|
49488
|
+
for (const root of new Set(roots)) {
|
|
49489
|
+
const report = await scanRoot(root, timeoutMs, signal2);
|
|
49490
|
+
if (report.warning) warnings.push(report.warning);
|
|
49491
|
+
for (const entry of report.entries) {
|
|
49492
|
+
if (entry.kind !== "PROJECT" || !entry.workspacePath || !isAbsolute6(entry.workspacePath) || entry.name.toLowerCase().endsWith(".noindex"))
|
|
49493
|
+
continue;
|
|
49494
|
+
if (!within(folder, resolve7(entry.workspacePath)) || within(folder, entry.path))
|
|
49495
|
+
continue;
|
|
49496
|
+
try {
|
|
49497
|
+
const workspace = await realpath6(entry.workspacePath);
|
|
49498
|
+
if (!within(folder, workspace)) continue;
|
|
49499
|
+
} catch (error) {
|
|
49500
|
+
if (error.code !== "ENOENT") {
|
|
49501
|
+
warnings.push(`${entry.path}: ${errorMessage(error)}`);
|
|
49502
|
+
continue;
|
|
49503
|
+
}
|
|
49504
|
+
let ancestor = dirname8(entry.workspacePath);
|
|
49505
|
+
while (within(folder, ancestor) && ancestor !== folder) {
|
|
49506
|
+
try {
|
|
49507
|
+
if (!within(folder, await realpath6(ancestor))) ancestor = "";
|
|
49508
|
+
break;
|
|
49509
|
+
} catch (parentError) {
|
|
49510
|
+
if (parentError.code !== "ENOENT") {
|
|
49511
|
+
ancestor = "";
|
|
49512
|
+
break;
|
|
49513
|
+
}
|
|
49514
|
+
ancestor = dirname8(ancestor);
|
|
49515
|
+
}
|
|
49516
|
+
}
|
|
49517
|
+
if (!ancestor) continue;
|
|
49518
|
+
}
|
|
49519
|
+
targets.push({ path: entry.path, rootPath: entry.rootPath });
|
|
49520
|
+
}
|
|
49521
|
+
}
|
|
49522
|
+
return { targets, warnings };
|
|
49523
|
+
}
|
|
49391
49524
|
function assertDirectChild(rootPath2, path) {
|
|
49392
49525
|
if (!isAbsolute6(rootPath2) || !isAbsolute6(path)) {
|
|
49393
49526
|
throw new Error("Build Data targets must use absolute paths");
|
|
@@ -49636,7 +49769,7 @@ import {
|
|
|
49636
49769
|
writeFile as writeFile8
|
|
49637
49770
|
} from "node:fs/promises";
|
|
49638
49771
|
import { homedir as homedir13 } from "node:os";
|
|
49639
|
-
import { dirname as dirname9, isAbsolute as isAbsolute7, join as join17, relative as
|
|
49772
|
+
import { dirname as dirname9, isAbsolute as isAbsolute7, join as join17, relative as relative8, resolve as resolve8, sep as sep8 } from "node:path";
|
|
49640
49773
|
import { promisify as promisify3 } from "node:util";
|
|
49641
49774
|
var executeFile = promisify3(execFile3);
|
|
49642
49775
|
var successfulProcess8 = {
|
|
@@ -49742,7 +49875,7 @@ async function listPackageFiles(skillDirectory) {
|
|
|
49742
49875
|
const metadata = await lstat4(path);
|
|
49743
49876
|
if (metadata.isSymbolicLink()) {
|
|
49744
49877
|
throw new Error(
|
|
49745
|
-
`Nested symbolic link is not supported: ${
|
|
49878
|
+
`Nested symbolic link is not supported: ${relative8(skillDirectory, path)}`
|
|
49746
49879
|
);
|
|
49747
49880
|
}
|
|
49748
49881
|
if (metadata.isDirectory()) {
|
|
@@ -49754,14 +49887,14 @@ async function listPackageFiles(skillDirectory) {
|
|
|
49754
49887
|
throw new Error("Skill contains too many files");
|
|
49755
49888
|
if (metadata.size > MAX_SKILL_FILE_BYTES) {
|
|
49756
49889
|
throw new Error(
|
|
49757
|
-
`${
|
|
49890
|
+
`${relative8(skillDirectory, path)} exceeds the per-file limit`
|
|
49758
49891
|
);
|
|
49759
49892
|
}
|
|
49760
49893
|
totalBytes += metadata.size;
|
|
49761
49894
|
if (totalBytes > MAX_SKILL_PACKAGE_BYTES)
|
|
49762
49895
|
throw new Error("Skill exceeds the package size limit");
|
|
49763
49896
|
files.push({
|
|
49764
|
-
path:
|
|
49897
|
+
path: relative8(skillDirectory, path).split(sep8).join("/"),
|
|
49765
49898
|
contentsBase64: (await readFile8(path)).toString("base64"),
|
|
49766
49899
|
executable: (metadata.mode & 73) !== 0
|
|
49767
49900
|
});
|
|
@@ -49840,7 +49973,7 @@ async function scanRoot2(location, configured, targets, warnings) {
|
|
|
49840
49973
|
const directory = join17(root, entry.name);
|
|
49841
49974
|
try {
|
|
49842
49975
|
const skillPackage = await readPackage(directory, resolvedRoot);
|
|
49843
|
-
const relativeDirectory = location.folder ?
|
|
49976
|
+
const relativeDirectory = location.folder ? relative8(location.folder, directory).split(sep8).join("/") : "";
|
|
49844
49977
|
installations.push({
|
|
49845
49978
|
...location,
|
|
49846
49979
|
codebaseId: target2?.codebaseId ?? null,
|
|
@@ -49967,7 +50100,7 @@ ${MANAGED_EXCLUDE_END}` : "";
|
|
|
49967
50100
|
}
|
|
49968
50101
|
async function assertUntracked(location, skillDirectory) {
|
|
49969
50102
|
if (location.scope !== "PROJECT") return;
|
|
49970
|
-
const relativeDirectory =
|
|
50103
|
+
const relativeDirectory = relative8(location.folder, skillDirectory).split(sep8).join("/");
|
|
49971
50104
|
if (await trackedProjectPath(location.folder, relativeDirectory)) {
|
|
49972
50105
|
throw new Error(
|
|
49973
50106
|
`${relativeDirectory} is tracked by Git and cannot be managed automatically`
|
|
@@ -50041,7 +50174,7 @@ var applySkills = async (payload) => {
|
|
|
50041
50174
|
if (operation.scope === "PROJECT" && operation.manageGitExclude) {
|
|
50042
50175
|
await updateManagedExclude(
|
|
50043
50176
|
operation.folder,
|
|
50044
|
-
|
|
50177
|
+
relative8(operation.folder, destination),
|
|
50045
50178
|
operation.kind === "WRITE"
|
|
50046
50179
|
);
|
|
50047
50180
|
}
|
|
@@ -50452,7 +50585,7 @@ var runWorkflowGitCheckpoint = async (payloadValue, _timeoutMs, signal2) => {
|
|
|
50452
50585
|
import { createWriteStream as createWriteStream3, watch } from "node:fs";
|
|
50453
50586
|
import { mkdtemp as mkdtemp9, open as open3, readFile as readFile11, realpath as realpath10, rm as rm18, stat as stat11 } from "node:fs/promises";
|
|
50454
50587
|
import { tmpdir as tmpdir9 } from "node:os";
|
|
50455
|
-
import { basename as basename5, dirname as dirname11, isAbsolute as isAbsolute9, join as join21, relative as
|
|
50588
|
+
import { basename as basename5, dirname as dirname11, isAbsolute as isAbsolute9, join as join21, relative as relative10 } from "node:path";
|
|
50456
50589
|
import { spawn as spawn9 } from "node:child_process";
|
|
50457
50590
|
|
|
50458
50591
|
// src/handlers/worktree-preparations.ts
|
|
@@ -50466,7 +50599,7 @@ import {
|
|
|
50466
50599
|
rm as rm17,
|
|
50467
50600
|
writeFile as writeFile10
|
|
50468
50601
|
} from "node:fs/promises";
|
|
50469
|
-
import { dirname as dirname10, isAbsolute as isAbsolute8, join as join20, relative as
|
|
50602
|
+
import { dirname as dirname10, isAbsolute as isAbsolute8, join as join20, relative as relative9, resolve as resolve9 } from "node:path";
|
|
50470
50603
|
var EXCLUDE_BEGIN = "# BEGIN AIDE PREPARATIONS";
|
|
50471
50604
|
var EXCLUDE_END = "# END AIDE PREPARATIONS";
|
|
50472
50605
|
function cleanError3(value) {
|
|
@@ -50508,7 +50641,7 @@ async function exists(path) {
|
|
|
50508
50641
|
async function safeTarget(folder, path) {
|
|
50509
50642
|
const root = await realpath9(folder);
|
|
50510
50643
|
const target2 = resolve9(root, path);
|
|
50511
|
-
const fromRoot =
|
|
50644
|
+
const fromRoot = relative9(root, target2);
|
|
50512
50645
|
if (!fromRoot || fromRoot.startsWith("..") || isAbsolute8(fromRoot) || path.includes("\0")) {
|
|
50513
50646
|
throw new Error(
|
|
50514
50647
|
"Preparation path must be an exact file inside the worktree"
|
|
@@ -51300,7 +51433,7 @@ async function inspectWorktreeItem(folderValue2, rootFolder, baseBranch, primary
|
|
|
51300
51433
|
return {
|
|
51301
51434
|
gitDirectory: gitDir,
|
|
51302
51435
|
folder,
|
|
51303
|
-
relativePath:
|
|
51436
|
+
relativePath: relative10(rootFolder, folder) || ".",
|
|
51304
51437
|
primary,
|
|
51305
51438
|
branch,
|
|
51306
51439
|
headSha: headResult.exitCode === 0 ? headResult.stdout.trim() : null,
|
|
@@ -51328,7 +51461,7 @@ async function inspectWorktreeItem(folderValue2, rootFolder, baseBranch, primary
|
|
|
51328
51461
|
return {
|
|
51329
51462
|
gitDirectory: folderValue2,
|
|
51330
51463
|
folder: folderValue2,
|
|
51331
|
-
relativePath:
|
|
51464
|
+
relativePath: relative10(rootFolder, folderValue2) || ".",
|
|
51332
51465
|
primary,
|
|
51333
51466
|
branch: null,
|
|
51334
51467
|
headSha: null,
|
|
@@ -51782,7 +51915,7 @@ async function availableSide(side, folder, timeoutMs, signal2) {
|
|
|
51782
51915
|
}
|
|
51783
51916
|
try {
|
|
51784
51917
|
const resolved = await realpath10(side.path);
|
|
51785
|
-
const difference =
|
|
51918
|
+
const difference = relative10(folder, resolved);
|
|
51786
51919
|
return difference !== ".." && !difference.startsWith("../") && (await stat11(resolved)).isFile();
|
|
51787
51920
|
} catch {
|
|
51788
51921
|
return false;
|
|
@@ -52019,7 +52152,7 @@ var downloadWorktreeDiffAsset = async (payload, timeoutMs, signal2, _onLog, cont
|
|
|
52019
52152
|
try {
|
|
52020
52153
|
if (selected.kind === "FILE") {
|
|
52021
52154
|
uploadPath = await realpath10(selected.path);
|
|
52022
|
-
const difference =
|
|
52155
|
+
const difference = relative10(folder, uploadPath);
|
|
52023
52156
|
if (difference === ".." || difference.startsWith("../")) {
|
|
52024
52157
|
throw new Error("Diff image resolves outside the worktree");
|
|
52025
52158
|
}
|
|
@@ -53013,6 +53146,26 @@ var deleteWorktree = async (payload, timeoutMs, signal2) => {
|
|
|
53013
53146
|
requireSuccess4(remote, `Could not inspect origin/${branch}`);
|
|
53014
53147
|
}
|
|
53015
53148
|
}
|
|
53149
|
+
const buildDataCleanup = {
|
|
53150
|
+
deleted: [],
|
|
53151
|
+
warnings: []
|
|
53152
|
+
};
|
|
53153
|
+
let buildDataTargets = [];
|
|
53154
|
+
try {
|
|
53155
|
+
const owned = await ownedWorktreeBuildData(
|
|
53156
|
+
folder,
|
|
53157
|
+
input.derivedData,
|
|
53158
|
+
timeoutMs,
|
|
53159
|
+
signal2
|
|
53160
|
+
);
|
|
53161
|
+
buildDataTargets = owned.targets;
|
|
53162
|
+
buildDataCleanup.warnings.push(...owned.warnings);
|
|
53163
|
+
} catch (error) {
|
|
53164
|
+
signal2.throwIfAborted();
|
|
53165
|
+
buildDataCleanup.warnings.push(
|
|
53166
|
+
`Could not inspect Xcode build data: ${error instanceof Error ? error.message : String(error)}`
|
|
53167
|
+
);
|
|
53168
|
+
}
|
|
53016
53169
|
requireSuccess4(
|
|
53017
53170
|
await git4(
|
|
53018
53171
|
rootFolder,
|
|
@@ -53022,6 +53175,26 @@ var deleteWorktree = async (payload, timeoutMs, signal2) => {
|
|
|
53022
53175
|
),
|
|
53023
53176
|
"Could not remove the worktree"
|
|
53024
53177
|
);
|
|
53178
|
+
if (buildDataTargets.length) {
|
|
53179
|
+
try {
|
|
53180
|
+
const result = await deleteBuildData(
|
|
53181
|
+
{ targets: buildDataTargets },
|
|
53182
|
+
timeoutMs,
|
|
53183
|
+
signal2,
|
|
53184
|
+
async () => void 0
|
|
53185
|
+
);
|
|
53186
|
+
buildDataCleanup.deleted.push(...result.deleted);
|
|
53187
|
+
buildDataCleanup.warnings.push(
|
|
53188
|
+
...result.deleted.filter((entry) => !entry.deleted).map(
|
|
53189
|
+
(entry) => `${entry.path}: ${entry.error ?? "Could not remove Xcode build data"}`
|
|
53190
|
+
)
|
|
53191
|
+
);
|
|
53192
|
+
} catch (error) {
|
|
53193
|
+
buildDataCleanup.warnings.push(
|
|
53194
|
+
`Could not remove Xcode build data: ${error instanceof Error ? error.message : String(error)}`
|
|
53195
|
+
);
|
|
53196
|
+
}
|
|
53197
|
+
}
|
|
53025
53198
|
if (branch && await refExists(rootFolder, `refs/heads/${branch}`, timeoutMs, signal2)) {
|
|
53026
53199
|
requireSuccess4(
|
|
53027
53200
|
await git4(rootFolder, ["branch", "-D", branch], timeoutMs, signal2),
|
|
@@ -53033,7 +53206,8 @@ var deleteWorktree = async (payload, timeoutMs, signal2) => {
|
|
|
53033
53206
|
moveId: input.moveId,
|
|
53034
53207
|
deleted: true,
|
|
53035
53208
|
branch,
|
|
53036
|
-
remoteBranchDeleted: input.deleteRemoteBranch
|
|
53209
|
+
remoteBranchDeleted: input.deleteRemoteBranch,
|
|
53210
|
+
buildDataCleanup
|
|
53037
53211
|
};
|
|
53038
53212
|
};
|
|
53039
53213
|
var operateWorktree = async (payload, timeoutMs, signal2) => {
|
|
@@ -53362,6 +53536,145 @@ var operateWorktree = async (payload, timeoutMs, signal2) => {
|
|
|
53362
53536
|
worktree: await worktreeResult()
|
|
53363
53537
|
};
|
|
53364
53538
|
};
|
|
53539
|
+
async function syncReviewedBranch(input, folder, timeoutMs, signal2) {
|
|
53540
|
+
const guard = input.mergeGuard;
|
|
53541
|
+
const run = async (args, message2) => {
|
|
53542
|
+
const result2 = await git4(folder, args, timeoutMs, signal2);
|
|
53543
|
+
if (result2.exitCode !== 0)
|
|
53544
|
+
throw new Error(
|
|
53545
|
+
`${message2}: ${cleanError4(result2.stderr || result2.stdout)}`
|
|
53546
|
+
);
|
|
53547
|
+
return result2;
|
|
53548
|
+
};
|
|
53549
|
+
const head = async () => (await run(["rev-parse", "HEAD"], "Could not read HEAD")).stdout.trim();
|
|
53550
|
+
const clean2 = async () => {
|
|
53551
|
+
if ((await run(
|
|
53552
|
+
["status", "--porcelain=v1", "-z"],
|
|
53553
|
+
"Could not inspect changes"
|
|
53554
|
+
)).stdout)
|
|
53555
|
+
throw new Error("Stash or commit changes before Auto Merge can sync");
|
|
53556
|
+
};
|
|
53557
|
+
if (await head() !== guard.expectedHeadSha)
|
|
53558
|
+
throw new Error(
|
|
53559
|
+
"The worktree source commit changed. Review it before resuming Auto Merge."
|
|
53560
|
+
);
|
|
53561
|
+
await clean2();
|
|
53562
|
+
const remoteHead = (await run(
|
|
53563
|
+
[
|
|
53564
|
+
"ls-remote",
|
|
53565
|
+
"--heads",
|
|
53566
|
+
"--",
|
|
53567
|
+
"origin",
|
|
53568
|
+
`refs/heads/${input.expectedBranch}`
|
|
53569
|
+
],
|
|
53570
|
+
"Could not read the remote source revision"
|
|
53571
|
+
)).stdout.trim().split(/\s+/)[0];
|
|
53572
|
+
if (remoteHead !== guard.expectedHeadSha)
|
|
53573
|
+
throw new Error(
|
|
53574
|
+
"The remote source commit changed. Review it before resuming Auto Merge."
|
|
53575
|
+
);
|
|
53576
|
+
const targetOrigin = normalizeGitOrigin(guard.targetUrl).canonicalOrigin;
|
|
53577
|
+
let targetTransport = targetOrigin === input.expectedOrigin ? "origin" : guard.targetUrl;
|
|
53578
|
+
if (targetTransport !== "origin" && /^https?:/.test(guard.targetUrl)) {
|
|
53579
|
+
const sourceUrl = (await run(["remote", "get-url", "origin"], "Could not read origin")).stdout.trim();
|
|
53580
|
+
const targetUrl = new URL(guard.targetUrl);
|
|
53581
|
+
if (sourceUrl.startsWith("ssh://")) {
|
|
53582
|
+
const source = new URL(sourceUrl);
|
|
53583
|
+
if (source.hostname === targetUrl.hostname) {
|
|
53584
|
+
source.pathname = targetUrl.pathname;
|
|
53585
|
+
targetTransport = source.toString();
|
|
53586
|
+
}
|
|
53587
|
+
} else {
|
|
53588
|
+
const source = /^([^@]+@([^:]+)):/.exec(sourceUrl);
|
|
53589
|
+
if (source?.[2] === targetUrl.hostname)
|
|
53590
|
+
targetTransport = `${source[1]}:${targetUrl.pathname.replace(/^\//, "")}`;
|
|
53591
|
+
}
|
|
53592
|
+
}
|
|
53593
|
+
await run(
|
|
53594
|
+
[
|
|
53595
|
+
"fetch",
|
|
53596
|
+
"--no-tags",
|
|
53597
|
+
"--no-write-fetch-head",
|
|
53598
|
+
"--",
|
|
53599
|
+
targetTransport,
|
|
53600
|
+
guard.targetSha
|
|
53601
|
+
],
|
|
53602
|
+
"Could not fetch the merge target"
|
|
53603
|
+
);
|
|
53604
|
+
const syncedTargetSha = guard.targetSha;
|
|
53605
|
+
const ancestor = await git4(
|
|
53606
|
+
folder,
|
|
53607
|
+
["merge-base", "--is-ancestor", syncedTargetSha, "HEAD"],
|
|
53608
|
+
timeoutMs,
|
|
53609
|
+
signal2
|
|
53610
|
+
);
|
|
53611
|
+
if (ancestor.exitCode !== 0 && ancestor.exitCode !== 1)
|
|
53612
|
+
throw new Error("Could not compare the merge target");
|
|
53613
|
+
const result = async (outcome) => ({
|
|
53614
|
+
...successfulProcess9,
|
|
53615
|
+
outcome,
|
|
53616
|
+
previousHeadSha: guard.expectedHeadSha,
|
|
53617
|
+
syncedHeadSha: await head(),
|
|
53618
|
+
syncedTargetSha,
|
|
53619
|
+
checkedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
53620
|
+
preparations: await executeWorktreePreparations(
|
|
53621
|
+
folder,
|
|
53622
|
+
input.preparations,
|
|
53623
|
+
"INSPECT",
|
|
53624
|
+
timeoutMs,
|
|
53625
|
+
signal2
|
|
53626
|
+
),
|
|
53627
|
+
worktree: await inspectWorktreeItem(
|
|
53628
|
+
folder,
|
|
53629
|
+
folder,
|
|
53630
|
+
input.baseBranch,
|
|
53631
|
+
false,
|
|
53632
|
+
Math.min(timeoutMs, 3e4),
|
|
53633
|
+
signal2
|
|
53634
|
+
)
|
|
53635
|
+
});
|
|
53636
|
+
if (await head() !== guard.expectedHeadSha)
|
|
53637
|
+
throw new Error("The worktree source commit changed during sync");
|
|
53638
|
+
await clean2();
|
|
53639
|
+
if (ancestor.exitCode === 0) return result("NO_CHANGE");
|
|
53640
|
+
const paths = await preparationConflictPaths(
|
|
53641
|
+
folder,
|
|
53642
|
+
input.preparations,
|
|
53643
|
+
syncedTargetSha,
|
|
53644
|
+
timeoutMs,
|
|
53645
|
+
signal2
|
|
53646
|
+
);
|
|
53647
|
+
if (paths.length)
|
|
53648
|
+
return {
|
|
53649
|
+
...await result("PREPARATION_CONFLICT"),
|
|
53650
|
+
preparationConflictPaths: paths
|
|
53651
|
+
};
|
|
53652
|
+
const rebase = await git4(
|
|
53653
|
+
folder,
|
|
53654
|
+
["rebase", syncedTargetSha],
|
|
53655
|
+
timeoutMs,
|
|
53656
|
+
signal2
|
|
53657
|
+
);
|
|
53658
|
+
if (rebase.exitCode !== 0) {
|
|
53659
|
+
if (await rebaseInProgress(folder, timeoutMs, signal2))
|
|
53660
|
+
return result("CONFLICT");
|
|
53661
|
+
throw new Error(cleanError4(rebase.stderr || "Auto Merge rebase failed"));
|
|
53662
|
+
}
|
|
53663
|
+
const syncedHeadSha = await head();
|
|
53664
|
+
await clean2();
|
|
53665
|
+
await run(
|
|
53666
|
+
[
|
|
53667
|
+
"push",
|
|
53668
|
+
`--force-with-lease=refs/heads/${input.expectedBranch}:${guard.expectedHeadSha}`,
|
|
53669
|
+
"origin",
|
|
53670
|
+
`${syncedHeadSha}:refs/heads/${input.expectedBranch}`
|
|
53671
|
+
],
|
|
53672
|
+
"Auto Merge push failed; review the local and remote revisions before resuming"
|
|
53673
|
+
);
|
|
53674
|
+
if (await head() !== syncedHeadSha)
|
|
53675
|
+
throw new Error("The worktree source commit changed during push");
|
|
53676
|
+
return result("SYNCED");
|
|
53677
|
+
}
|
|
53365
53678
|
var autoSyncWorktree = async (payload, timeoutMs, signal2) => {
|
|
53366
53679
|
const input = worktreeAutoSyncJobPayload(payload);
|
|
53367
53680
|
const folder = await validateWorktree2(input, timeoutMs, signal2);
|
|
@@ -53398,6 +53711,8 @@ var autoSyncWorktree = async (payload, timeoutMs, signal2) => {
|
|
|
53398
53711
|
`Auto Sync expected branch ${input.expectedBranch}, but found ${branch ?? "detached HEAD"}`
|
|
53399
53712
|
);
|
|
53400
53713
|
}
|
|
53714
|
+
if (input.mergeGuard)
|
|
53715
|
+
return syncReviewedBranch(input, folder, timeoutMs, signal2);
|
|
53401
53716
|
const upstreamResult = branch ? await git4(
|
|
53402
53717
|
folder,
|
|
53403
53718
|
["rev-parse", "--abbrev-ref", "@{upstream}"],
|
|
@@ -54134,6 +54449,11 @@ var JobExecutor = class {
|
|
|
54134
54449
|
controller.signal
|
|
54135
54450
|
),
|
|
54136
54451
|
reportBuildProgress: (input) => this.client.reportBuildProgress(input),
|
|
54452
|
+
reportBuildDeploymentLaunched: (deploymentId, launchedAt) => this.client.reportBuildDeploymentLaunched(
|
|
54453
|
+
claimed.id,
|
|
54454
|
+
deploymentId,
|
|
54455
|
+
launchedAt
|
|
54456
|
+
),
|
|
54137
54457
|
appendBuildLogChunks: (buildId, chunks) => this.client.appendBuildLogChunks(buildId, chunks),
|
|
54138
54458
|
uploadBuildArtifact: (input) => this.client.uploadBuildArtifact(input),
|
|
54139
54459
|
uploadBuildArtifactTransfer: (input) => this.client.uploadBuildArtifactTransfer(input),
|