@rallycry/conveyor-agent 9.0.1 → 9.0.3
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.
|
@@ -830,6 +830,7 @@ function createServiceLogger(service) {
|
|
|
830
830
|
|
|
831
831
|
// src/runner/git-utils.ts
|
|
832
832
|
import { execSync } from "child_process";
|
|
833
|
+
import { realpathSync } from "fs";
|
|
833
834
|
function syncWithBaseBranch(cwd, baseBranch) {
|
|
834
835
|
if (!baseBranch) return true;
|
|
835
836
|
try {
|
|
@@ -1057,7 +1058,18 @@ function restoreWipSnapshot(cwd, branch) {
|
|
|
1057
1058
|
stdio: ["ignore", "pipe", "ignore"]
|
|
1058
1059
|
}).toString().trim();
|
|
1059
1060
|
const head = execSync("git rev-parse HEAD", { cwd, stdio: ["ignore", "pipe", "ignore"] }).toString().trim();
|
|
1060
|
-
if (parent !== head)
|
|
1061
|
+
if (parent !== head) {
|
|
1062
|
+
try {
|
|
1063
|
+
execSync(`git stash apply ${sha}`, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
1064
|
+
return "applied";
|
|
1065
|
+
} catch {
|
|
1066
|
+
try {
|
|
1067
|
+
execSync("git reset --merge", { cwd, stdio: "ignore" });
|
|
1068
|
+
} catch {
|
|
1069
|
+
}
|
|
1070
|
+
return "stale";
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1061
1073
|
execSync(`git stash apply ${sha}`, { cwd, stdio: ["ignore", "pipe", "pipe"] });
|
|
1062
1074
|
return "applied";
|
|
1063
1075
|
} catch {
|
|
@@ -1131,6 +1143,105 @@ async function pushToOrigin(cwd, refreshToken, skipVerify = false) {
|
|
|
1131
1143
|
return false;
|
|
1132
1144
|
}
|
|
1133
1145
|
}
|
|
1146
|
+
function branchBackupRef(branch) {
|
|
1147
|
+
return `conveyor-wip/branches/${branch}`;
|
|
1148
|
+
}
|
|
1149
|
+
function listWorktrees(cwd) {
|
|
1150
|
+
try {
|
|
1151
|
+
const out = execSync("git worktree list --porcelain", {
|
|
1152
|
+
cwd,
|
|
1153
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1154
|
+
}).toString();
|
|
1155
|
+
const result = [];
|
|
1156
|
+
for (const entry of out.split("\n\n")) {
|
|
1157
|
+
const lines = entry.trim().split("\n");
|
|
1158
|
+
const wl = lines.find((l) => l.startsWith("worktree "));
|
|
1159
|
+
if (!wl) continue;
|
|
1160
|
+
const bl = lines.find((l) => l.startsWith("branch "));
|
|
1161
|
+
result.push({
|
|
1162
|
+
path: wl.slice("worktree ".length),
|
|
1163
|
+
branch: bl ? bl.slice("branch refs/heads/".length) : null
|
|
1164
|
+
});
|
|
1165
|
+
}
|
|
1166
|
+
return result;
|
|
1167
|
+
} catch {
|
|
1168
|
+
return [];
|
|
1169
|
+
}
|
|
1170
|
+
}
|
|
1171
|
+
function listLocalBranches(cwd) {
|
|
1172
|
+
try {
|
|
1173
|
+
return execSync("git for-each-ref --format='%(refname:short)' refs/heads/", {
|
|
1174
|
+
cwd,
|
|
1175
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1176
|
+
}).toString().split("\n").map((s) => s.trim()).filter(Boolean);
|
|
1177
|
+
} catch {
|
|
1178
|
+
return [];
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
function branchUnpushedCount(cwd, branch) {
|
|
1182
|
+
try {
|
|
1183
|
+
const n = execSync(`git rev-list --count ${JSON.stringify(branch)} --not --remotes=origin`, {
|
|
1184
|
+
cwd,
|
|
1185
|
+
stdio: ["ignore", "pipe", "ignore"]
|
|
1186
|
+
}).toString().trim();
|
|
1187
|
+
return Number.parseInt(n, 10) || 0;
|
|
1188
|
+
} catch {
|
|
1189
|
+
return 0;
|
|
1190
|
+
}
|
|
1191
|
+
}
|
|
1192
|
+
function samePath(a, b) {
|
|
1193
|
+
try {
|
|
1194
|
+
return realpathSync(a) === realpathSync(b);
|
|
1195
|
+
} catch {
|
|
1196
|
+
return a === b;
|
|
1197
|
+
}
|
|
1198
|
+
}
|
|
1199
|
+
async function flushAllPendingWork(cwd, opts) {
|
|
1200
|
+
try {
|
|
1201
|
+
const primary = await flushPendingChanges(cwd, opts);
|
|
1202
|
+
await refreshRemoteToken(cwd, opts?.refreshToken);
|
|
1203
|
+
const currentBranch = getCurrentBranch(cwd);
|
|
1204
|
+
const worktreesSnapshotted = snapshotOtherWorktrees(cwd, opts?.wipMessage);
|
|
1205
|
+
const branchesBackedUp = backupOtherBranches(cwd, currentBranch);
|
|
1206
|
+
return {
|
|
1207
|
+
hadWork: primary.hadWork || worktreesSnapshotted > 0 || branchesBackedUp > 0,
|
|
1208
|
+
branchesBackedUp,
|
|
1209
|
+
worktreesSnapshotted
|
|
1210
|
+
};
|
|
1211
|
+
} catch {
|
|
1212
|
+
return { hadWork: false, branchesBackedUp: 0, worktreesSnapshotted: 0 };
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
function snapshotOtherWorktrees(cwd, wipMessage) {
|
|
1216
|
+
let count = 0;
|
|
1217
|
+
for (const wt of listWorktrees(cwd)) {
|
|
1218
|
+
if (samePath(wt.path, cwd) || !wt.branch) continue;
|
|
1219
|
+
try {
|
|
1220
|
+
if (!hasUncommittedChanges(wt.path)) continue;
|
|
1221
|
+
const sha = createWipSnapshot(wt.path, wipMessage ?? "WIP: conveyor-agent snapshot");
|
|
1222
|
+
if (sha && tryPushRefspec(wt.path, `${sha}:refs/heads/${wipRefForBranch(wt.branch)}`, true)) {
|
|
1223
|
+
wipRefPushed.add(wt.path);
|
|
1224
|
+
count++;
|
|
1225
|
+
}
|
|
1226
|
+
} catch {
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
return count;
|
|
1230
|
+
}
|
|
1231
|
+
function backupOtherBranches(cwd, currentBranch) {
|
|
1232
|
+
let count = 0;
|
|
1233
|
+
for (const branch of listLocalBranches(cwd)) {
|
|
1234
|
+
if (branch === currentBranch || branch.startsWith("conveyor-wip/")) continue;
|
|
1235
|
+
try {
|
|
1236
|
+
if (branchUnpushedCount(cwd, branch) === 0) continue;
|
|
1237
|
+
if (tryPushRefspec(cwd, `refs/heads/${branch}:refs/heads/${branchBackupRef(branch)}`, true)) {
|
|
1238
|
+
count++;
|
|
1239
|
+
}
|
|
1240
|
+
} catch {
|
|
1241
|
+
}
|
|
1242
|
+
}
|
|
1243
|
+
return count;
|
|
1244
|
+
}
|
|
1134
1245
|
|
|
1135
1246
|
// src/runner/plan-sync.ts
|
|
1136
1247
|
import { readdirSync, statSync, readFileSync } from "fs";
|
|
@@ -2982,6 +3093,8 @@ function buildPromptBytes(text) {
|
|
|
2982
3093
|
var SUBMIT_SETTLE_MS = 300;
|
|
2983
3094
|
var SUBMIT_NUDGE_INTERVAL_MS = 2e3;
|
|
2984
3095
|
var SUBMIT_NUDGE_MAX_PRESSES = 5;
|
|
3096
|
+
var SUBMIT_NUDGE_SLOW_INTERVAL_MS = 5e3;
|
|
3097
|
+
var SUBMIT_NUDGE_WINDOW_MS = 9e4;
|
|
2985
3098
|
function sleep2(ms) {
|
|
2986
3099
|
return new Promise((resolve) => {
|
|
2987
3100
|
setTimeout(resolve, ms);
|
|
@@ -3230,18 +3343,28 @@ var PtySession = class {
|
|
|
3230
3343
|
* Deliberate trade-off (same as the plan-dialog auto-accept below): a press
|
|
3231
3344
|
* can accept the default of an unexpected startup dialog — in a headless
|
|
3232
3345
|
* pod that unblocks the run rather than parking it forever.
|
|
3346
|
+
*
|
|
3347
|
+
* Two phases: SUBMIT_NUDGE_MAX_PRESSES fast presses for the swallowed-Enter
|
|
3348
|
+
* race, then a slow cadence out to SUBMIT_NUDGE_WINDOW_MS for startup
|
|
3349
|
+
* dialogs that render late on cold pods (the folder-trust dialog's default
|
|
3350
|
+
* is the accept option, so one late Enter un-parks the run).
|
|
3233
3351
|
*/
|
|
3234
3352
|
armSubmitNudge() {
|
|
3235
3353
|
if (this.submitNudgeTimer) return;
|
|
3236
3354
|
this.pendingSubmitNudge = true;
|
|
3355
|
+
const startedAt = Date.now();
|
|
3237
3356
|
let presses = 0;
|
|
3238
3357
|
const press = () => {
|
|
3239
|
-
if (this._toreDown || !this.pendingSubmitNudge ||
|
|
3358
|
+
if (this._toreDown || !this.pendingSubmitNudge || Date.now() - startedAt >= SUBMIT_NUDGE_WINDOW_MS) {
|
|
3240
3359
|
this.disarmSubmitNudge();
|
|
3241
3360
|
return;
|
|
3242
3361
|
}
|
|
3243
3362
|
presses++;
|
|
3244
3363
|
this.writeStdin("\r");
|
|
3364
|
+
if (presses === SUBMIT_NUDGE_MAX_PRESSES && this.submitNudgeTimer) {
|
|
3365
|
+
clearInterval(this.submitNudgeTimer);
|
|
3366
|
+
this.submitNudgeTimer = setInterval(press, SUBMIT_NUDGE_SLOW_INTERVAL_MS);
|
|
3367
|
+
}
|
|
3245
3368
|
};
|
|
3246
3369
|
this.submitNudgeTimer = setInterval(press, SUBMIT_NUDGE_INTERVAL_MS);
|
|
3247
3370
|
}
|
|
@@ -3467,6 +3590,18 @@ async function ensureClaudeOnboarding(env = process.env, trustCwd) {
|
|
|
3467
3590
|
const contents = planClaudeJsonSeed(await readRaw(path), trustCwd);
|
|
3468
3591
|
if (contents === null) return;
|
|
3469
3592
|
await writeFile3(path, contents, "utf8");
|
|
3593
|
+
const verify = await readRaw(path);
|
|
3594
|
+
if (verify === contents) {
|
|
3595
|
+
process.stderr.write(
|
|
3596
|
+
`[conveyor-agent] claude onboarding seeded${trustCwd ? ` (trust: ${trustCwd})` : ""}
|
|
3597
|
+
`
|
|
3598
|
+
);
|
|
3599
|
+
} else {
|
|
3600
|
+
process.stderr.write(
|
|
3601
|
+
`[conveyor-agent] claude onboarding seed read-back MISMATCH at ${path}: wrote ${contents.length}B, read ${verify?.length ?? 0}B \u2014 CLI may see stale config and park at a startup dialog
|
|
3602
|
+
`
|
|
3603
|
+
);
|
|
3604
|
+
}
|
|
3470
3605
|
} catch (err) {
|
|
3471
3606
|
const message = err instanceof Error ? err.message : String(err);
|
|
3472
3607
|
process.stderr.write(`[conveyor-agent] claude onboarding seed failed: ${message}
|
|
@@ -8217,7 +8352,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
8217
8352
|
if (this.periodicFlushInFlight || this.stopped) return;
|
|
8218
8353
|
this.periodicFlushInFlight = true;
|
|
8219
8354
|
try {
|
|
8220
|
-
const result = await
|
|
8355
|
+
const result = await flushAllPendingWork(this.config.workspaceDir, {
|
|
8221
8356
|
wipMessage: "WIP: periodic auto-commit",
|
|
8222
8357
|
refreshToken: async () => {
|
|
8223
8358
|
try {
|
|
@@ -8232,7 +8367,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
8232
8367
|
});
|
|
8233
8368
|
if (result.hadWork) {
|
|
8234
8369
|
process.stderr.write(
|
|
8235
|
-
`[conveyor-agent] Periodic git flush:
|
|
8370
|
+
`[conveyor-agent] Periodic git flush: branchesBackedUp=${result.branchesBackedUp} worktreesSnapshotted=${result.worktreesSnapshotted}
|
|
8236
8371
|
`
|
|
8237
8372
|
);
|
|
8238
8373
|
}
|
|
@@ -8246,7 +8381,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
8246
8381
|
* connection is still alive for token refresh. Never throws. */
|
|
8247
8382
|
async flushGitOnShutdown() {
|
|
8248
8383
|
try {
|
|
8249
|
-
const result = await
|
|
8384
|
+
const result = await flushAllPendingWork(this.config.workspaceDir, {
|
|
8250
8385
|
wipMessage: "WIP: auto-commit on conveyor-agent shutdown",
|
|
8251
8386
|
refreshToken: async () => {
|
|
8252
8387
|
try {
|
|
@@ -8261,7 +8396,7 @@ var SessionRunner = class _SessionRunner {
|
|
|
8261
8396
|
});
|
|
8262
8397
|
if (result.hadWork) {
|
|
8263
8398
|
process.stderr.write(
|
|
8264
|
-
`[conveyor-agent] Shutdown git flush:
|
|
8399
|
+
`[conveyor-agent] Shutdown git flush: branchesBackedUp=${result.branchesBackedUp} worktreesSnapshotted=${result.worktreesSnapshotted}
|
|
8265
8400
|
`
|
|
8266
8401
|
);
|
|
8267
8402
|
}
|
|
@@ -8758,4 +8893,4 @@ export {
|
|
|
8758
8893
|
runStartCommand,
|
|
8759
8894
|
unshallowRepo
|
|
8760
8895
|
};
|
|
8761
|
-
//# sourceMappingURL=chunk-
|
|
8896
|
+
//# sourceMappingURL=chunk-EYIGNRRW.js.map
|