automata-cli 0.1.0-feature-030-do-work.206 → 0.1.0-feature-030-do-work.210
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/index.js +108 -34
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -34,8 +34,9 @@ function writeDoWork(patch) {
|
|
|
34
34
|
writeConfig({ ...current, doWork: { ...current.doWork, ...patch } });
|
|
35
35
|
}
|
|
36
36
|
function parseNonNegativeInt(value, label) {
|
|
37
|
-
const
|
|
38
|
-
|
|
37
|
+
const trimmed = value.trim();
|
|
38
|
+
const parsed = Number.parseInt(trimmed, 10);
|
|
39
|
+
if (Number.isNaN(parsed) || parsed < 0 || String(parsed) !== trimmed || !Number.isSafeInteger(parsed)) {
|
|
39
40
|
process.stderr.write(`Error: ${label} must be a non-negative integer (got "${value}").
|
|
40
41
|
`);
|
|
41
42
|
process.exit(1);
|
|
@@ -722,7 +723,7 @@ function createTrackingBranch(branch) {
|
|
|
722
723
|
return gitCommand(["checkout", "-b", branch, `origin/${branch}`]);
|
|
723
724
|
}
|
|
724
725
|
function fetchBranch(branch) {
|
|
725
|
-
return gitCommand(["fetch", "origin", branch]);
|
|
726
|
+
return gitCommand(["fetch", "origin", `+refs/heads/${branch}:refs/remotes/origin/${branch}`]);
|
|
726
727
|
}
|
|
727
728
|
function pullFastForwardOnly(branch) {
|
|
728
729
|
return gitCommand(branch === void 0 ? ["pull", "--ff-only"] : ["pull", "--ff-only", "origin", branch]);
|
|
@@ -2494,6 +2495,7 @@ query($owner:String!,$repo:String!,$prNumber:Int!,$cursor:String){
|
|
|
2494
2495
|
nodes{
|
|
2495
2496
|
isResolved isOutdated path line
|
|
2496
2497
|
comments(last:100){
|
|
2498
|
+
pageInfo{ hasPreviousPage }
|
|
2497
2499
|
nodes{ author{login} body createdAt }
|
|
2498
2500
|
}
|
|
2499
2501
|
}
|
|
@@ -2531,6 +2533,11 @@ function getReviewThreads(prNumber) {
|
|
|
2531
2533
|
);
|
|
2532
2534
|
const connection = response.data.repository.pullRequest.reviewThreads;
|
|
2533
2535
|
for (const node of connection.nodes) {
|
|
2536
|
+
if (node.comments.pageInfo?.hasPreviousPage) {
|
|
2537
|
+
throw new Error(
|
|
2538
|
+
`Review thread on ${node.path} in pull request #${String(prNumber)} has more than 100 comments, so the earliest ones were not read. Refusing rather than risk suppressing a maintainer's request.`
|
|
2539
|
+
);
|
|
2540
|
+
}
|
|
2534
2541
|
threads.push({
|
|
2535
2542
|
path: node.path,
|
|
2536
2543
|
line: node.line ?? null,
|
|
@@ -2833,7 +2840,7 @@ function composePrompt(input) {
|
|
|
2833
2840
|
}
|
|
2834
2841
|
|
|
2835
2842
|
// src/run/runLock.ts
|
|
2836
|
-
import { writeFileSync, readFileSync as readFileSync3, unlinkSync, mkdirSync, renameSync } from "fs";
|
|
2843
|
+
import { writeFileSync, readFileSync as readFileSync3, unlinkSync, mkdirSync, renameSync, linkSync } from "fs";
|
|
2837
2844
|
import { randomUUID } from "crypto";
|
|
2838
2845
|
import { hostname } from "os";
|
|
2839
2846
|
import { join as join2 } from "path";
|
|
@@ -2885,8 +2892,26 @@ function makeHandle(path, token) {
|
|
|
2885
2892
|
if (current !== null && current.token !== token) {
|
|
2886
2893
|
return;
|
|
2887
2894
|
}
|
|
2895
|
+
const takenAway = `${path}.releasing.${token}`;
|
|
2896
|
+
try {
|
|
2897
|
+
renameSync(path, takenAway);
|
|
2898
|
+
} catch {
|
|
2899
|
+
return;
|
|
2900
|
+
}
|
|
2901
|
+
const owner = readOwner(takenAway);
|
|
2902
|
+
if (owner === null || owner.token === token) {
|
|
2903
|
+
try {
|
|
2904
|
+
unlinkSync(takenAway);
|
|
2905
|
+
} catch {
|
|
2906
|
+
}
|
|
2907
|
+
return;
|
|
2908
|
+
}
|
|
2888
2909
|
try {
|
|
2889
|
-
|
|
2910
|
+
linkSync(takenAway, path);
|
|
2911
|
+
} catch {
|
|
2912
|
+
}
|
|
2913
|
+
try {
|
|
2914
|
+
unlinkSync(takenAway);
|
|
2890
2915
|
} catch {
|
|
2891
2916
|
}
|
|
2892
2917
|
}
|
|
@@ -3043,8 +3068,8 @@ function resolveSettings(options) {
|
|
|
3043
3068
|
if (agentUser.length === 0) {
|
|
3044
3069
|
fail("No agent user configured. Run `automata config set agent-user <login>`.");
|
|
3045
3070
|
}
|
|
3071
|
+
validateDoWorkConfig(config.doWork);
|
|
3046
3072
|
const doWork = config.doWork ?? {};
|
|
3047
|
-
validateDoWorkConfig(doWork);
|
|
3048
3073
|
let executor = doWork.executor ?? DEFAULT_DO_WORK.executor;
|
|
3049
3074
|
if (options.with !== void 0) {
|
|
3050
3075
|
const requested = options.with.toLowerCase();
|
|
@@ -3136,33 +3161,49 @@ function describePlannedRun(item, settings, run5) {
|
|
|
3136
3161
|
];
|
|
3137
3162
|
return lines.join("\n") + "\n";
|
|
3138
3163
|
}
|
|
3139
|
-
function
|
|
3140
|
-
|
|
3141
|
-
|
|
3164
|
+
function isPlainObject(value) {
|
|
3165
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3166
|
+
}
|
|
3167
|
+
function validateOptionalString(container, key, path) {
|
|
3168
|
+
const value = container[key];
|
|
3169
|
+
if (value === void 0 || value === null) return;
|
|
3170
|
+
if (typeof value !== "string" || value.trim().length === 0) {
|
|
3171
|
+
fail(`${path} must be a non-empty string.`);
|
|
3142
3172
|
}
|
|
3143
|
-
|
|
3144
|
-
|
|
3173
|
+
}
|
|
3174
|
+
function validateOptionalInt(container, key, path, min, hint) {
|
|
3175
|
+
const value = container[key];
|
|
3176
|
+
if (value === void 0 || value === null) return;
|
|
3177
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < min) {
|
|
3178
|
+
fail(`${path} must be ${hint}, got ${JSON.stringify(value)}.`);
|
|
3145
3179
|
}
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
}
|
|
3180
|
+
}
|
|
3181
|
+
function validateDoWorkConfig(section) {
|
|
3182
|
+
if (section === void 0 || section === null) return;
|
|
3183
|
+
if (!isPlainObject(section)) {
|
|
3184
|
+
fail(`doWork must be an object, got ${JSON.stringify(section)}.`);
|
|
3152
3185
|
}
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
}
|
|
3186
|
+
const executor = section["executor"];
|
|
3187
|
+
if (executor !== void 0 && executor !== "claude" && executor !== "codex") {
|
|
3188
|
+
fail(`doWork.executor must be 'claude' or 'codex', got ${JSON.stringify(executor)}.`);
|
|
3157
3189
|
}
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
[
|
|
3163
|
-
|
|
3164
|
-
if (
|
|
3165
|
-
fail(
|
|
3190
|
+
validateOptionalString(section, "baseBranch", "doWork.baseBranch");
|
|
3191
|
+
validateOptionalInt(section, "maxRunsPerTick", "doWork.maxRunsPerTick", 0, "a non-negative integer (0 = unlimited)");
|
|
3192
|
+
validateOptionalInt(section, "lockStaleMinutes", "doWork.lockStaleMinutes", 1, "a positive integer");
|
|
3193
|
+
for (const container of ["models", "prompts"]) {
|
|
3194
|
+
const value = section[container];
|
|
3195
|
+
if (value === void 0 || value === null) continue;
|
|
3196
|
+
if (!isPlainObject(value)) {
|
|
3197
|
+
fail(`doWork.${container} must be an object, got ${JSON.stringify(value)}.`);
|
|
3198
|
+
}
|
|
3199
|
+
const keys = container === "models" ? ["claude", "codex"] : ["issueDiscuss", "prWork"];
|
|
3200
|
+
for (const key of keys) {
|
|
3201
|
+
validateOptionalString(value, key, `doWork.${container}.${key}`);
|
|
3202
|
+
}
|
|
3203
|
+
for (const key of Object.keys(value)) {
|
|
3204
|
+
if (!keys.includes(key)) {
|
|
3205
|
+
fail(`doWork.${container}.${key} is not a recognised setting; expected one of: ${keys.join(", ")}.`);
|
|
3206
|
+
}
|
|
3166
3207
|
}
|
|
3167
3208
|
}
|
|
3168
3209
|
}
|
|
@@ -3360,6 +3401,21 @@ async function processItem(planned, settings, silent) {
|
|
|
3360
3401
|
`);
|
|
3361
3402
|
}
|
|
3362
3403
|
}
|
|
3404
|
+
if (item.turn === "pr-work" && item.pr && item.issueAnalysis.hasNewMessage) {
|
|
3405
|
+
try {
|
|
3406
|
+
postMarker(
|
|
3407
|
+
"issue",
|
|
3408
|
+
item.issue.number,
|
|
3409
|
+
`automata do-work: picked this up on pull request #${String(item.pr.number)} \u2014 ${item.pr.url}`
|
|
3410
|
+
);
|
|
3411
|
+
progress(` noted on issue #${String(item.issue.number)} that the work is on pull request #${String(item.pr.number)}.
|
|
3412
|
+
`);
|
|
3413
|
+
} catch (err) {
|
|
3414
|
+
progress(` skipped: could not note the pickup on issue #${String(item.issue.number)} \u2014 ${err.message}
|
|
3415
|
+
`);
|
|
3416
|
+
return { ...base, outcome: "skipped", detail: `issue pickup note failed: ${err.message}` };
|
|
3417
|
+
}
|
|
3418
|
+
}
|
|
3363
3419
|
let marker;
|
|
3364
3420
|
const markerSurface = item.turn === "pr-work" && item.pr ? item.pr.number : item.issue.number;
|
|
3365
3421
|
try {
|
|
@@ -3410,10 +3466,15 @@ var doWorkCommand = new Command6("do-work").description(
|
|
|
3410
3466
|
const settings = resolveSettings(options);
|
|
3411
3467
|
const lock = acquireRunLock("do-work", settings.lockStaleMinutes);
|
|
3412
3468
|
if (!lock.ok) {
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
)
|
|
3469
|
+
const held = lock.heldBy;
|
|
3470
|
+
const sentence = `Another automata instance is already running here (pid ${String(held.pid)} on ${held.host}, started ${held.startedAt}, command ${held.command}). Doing nothing.
|
|
3471
|
+
`;
|
|
3472
|
+
if (options.json === true) {
|
|
3473
|
+
progress(sentence);
|
|
3474
|
+
out(JSON.stringify({ lockHeld: true, heldBy: held, plan: [], items: [], exitCode: 0 }, null, 2) + "\n");
|
|
3475
|
+
} else {
|
|
3476
|
+
out(sentence);
|
|
3477
|
+
}
|
|
3417
3478
|
return;
|
|
3418
3479
|
}
|
|
3419
3480
|
const handle = lock.handle;
|
|
@@ -3473,7 +3534,20 @@ ${describePlan(decisions)}`;
|
|
|
3473
3534
|
deferred.push(item);
|
|
3474
3535
|
continue;
|
|
3475
3536
|
}
|
|
3476
|
-
|
|
3537
|
+
let report;
|
|
3538
|
+
try {
|
|
3539
|
+
report = await processItem(item, settings, options.silent === true);
|
|
3540
|
+
} catch (err) {
|
|
3541
|
+
progress(` failed: ${err.message}
|
|
3542
|
+
`);
|
|
3543
|
+
report = {
|
|
3544
|
+
issue: item.issue.number,
|
|
3545
|
+
title: item.issue.title,
|
|
3546
|
+
turn: item.turn,
|
|
3547
|
+
outcome: "failed",
|
|
3548
|
+
detail: err.message
|
|
3549
|
+
};
|
|
3550
|
+
}
|
|
3477
3551
|
if (report.outcome !== "skipped") runsUsed++;
|
|
3478
3552
|
reports.push(report);
|
|
3479
3553
|
}
|