@tokenfactory/acc-runner 0.47.12 → 0.47.14
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/build-info.generated.d.ts +1 -1
- package/dist/build-info.generated.js +2 -2
- package/dist/doctor.d.ts +7 -0
- package/dist/doctor.d.ts.map +1 -1
- package/dist/doctor.js +34 -1
- package/dist/doctor.js.map +1 -1
- package/dist/mcp-spawn.d.ts +1 -1
- package/dist/mcp-spawn.js +1 -1
- package/dist/prepr-gate.d.ts +31 -0
- package/dist/prepr-gate.d.ts.map +1 -1
- package/dist/prepr-gate.js +81 -0
- package/dist/prepr-gate.js.map +1 -1
- package/dist/runtime/worktree.d.ts +25 -0
- package/dist/runtime/worktree.d.ts.map +1 -1
- package/dist/runtime/worktree.js +98 -0
- package/dist/runtime/worktree.js.map +1 -1
- package/dist/task-runner.d.ts.map +1 -1
- package/dist/task-runner.js +56 -29
- package/dist/task-runner.js.map +1 -1
- package/package.json +1 -1
package/dist/task-runner.js
CHANGED
|
@@ -45,7 +45,7 @@ import { acquireTaskLock as defaultAcquireTaskLock, clearLocalTaskLock as defaul
|
|
|
45
45
|
// RUNNER-HOOK-DIR-AND-LOCK-JANITOR-1: remove this task's commit-guard hooks dir
|
|
46
46
|
// on every exit path (the janitor is the hourly backstop for leaks a crash left).
|
|
47
47
|
import { removeTaskHookDir as defaultRemoveTaskHookDir } from "./runtime/janitor.js";
|
|
48
|
-
import { prepareTaskWorktree as defaultPrepareTaskWorktree, WorktreeBranchTakenError, } from "./runtime/worktree.js";
|
|
48
|
+
import { prepareTaskWorktree as defaultPrepareTaskWorktree, WorktreeBranchTakenError, findDanglingWarmCloneLinks, seedInstallSafeNodeModules, } from "./runtime/worktree.js";
|
|
49
49
|
// v0.21 T-66-1: serialize the per-task worktree-provisioning critical section
|
|
50
50
|
// against the shared clone so concurrent tasks can't collide on git's
|
|
51
51
|
// repo-global locks (the T-65-2 race).
|
|
@@ -58,7 +58,7 @@ import { clonePathForRepo, ensureRepoClone, CloneFailedError, } from "./runtime/
|
|
|
58
58
|
import { parseConflictMeta, resolveConflict, MAX_CONFLICT_ATTEMPTS, } from "./runtime/conflict-resolver.js";
|
|
59
59
|
import { MAX_REWORK_CYCLES, parseReworkMeta, renderReworkPrompt, reconcileReworkBranch as defaultReconcileReworkBranch, fetchPrHeadRef as defaultFetchPrHeadRef, } from "./runtime/rework.js";
|
|
60
60
|
import { assertResolutionIntegrity, isConflictResolutionTask, summariseFailures, } from "./runtime/resolution-integrity.js";
|
|
61
|
-
import { depsMissingGateResult, depsStaleGateResult, gateFailureBlockReason, gateRunnerCrashResult, runPreprGate as defaultRunPreprGate, DEPS_MISSING_CLASSIFICATION, DEPS_STALE_CLASSIFICATION, GATE_TOOL_CRASHED_CLASSIFICATION, PREPR_GATE_FAILED_CLASSIFICATION, PREPR_GATES, } from "./prepr-gate.js";
|
|
61
|
+
import { depsMissingGateResult, depsStaleGateResult, gateFailureBlockReason, gateRunnerCrashResult, runPreprGate as defaultRunPreprGate, classifyDanglingParentDeps, DEPS_MISSING_CLASSIFICATION, DEPS_STALE_CLASSIFICATION, GATE_TOOL_CRASHED_CLASSIFICATION, PREPR_GATE_FAILED_CLASSIFICATION, PREPR_GATES, } from "./prepr-gate.js";
|
|
62
62
|
import { revalidateMigrationSeq as defaultRevalidateMigrationSeq, } from "./migration-seq-guard.js";
|
|
63
63
|
import { readAppliedMigrationSeqs } from "./applied-seq-roster.js";
|
|
64
64
|
import { commitGuardSkipRequested, gitConfigHooksEnv, installCommitGuardSync, } from "./commit-guard.js";
|
|
@@ -364,10 +364,13 @@ export async function ensureWorktreeNodeModules(workdir, repoPath, opts = {}) {
|
|
|
364
364
|
try {
|
|
365
365
|
if (!(await worktreePathExists(src)))
|
|
366
366
|
continue; // parent has no deps here
|
|
367
|
-
|
|
367
|
+
// A resumed worktree seeded by an older runner holds ONE link to `src`: replace it.
|
|
368
|
+
const prior = await fs.promises.lstat(dst).catch(() => null);
|
|
369
|
+
if (prior && !prior.isSymbolicLink())
|
|
368
370
|
continue; // already present (resume/prior seed)
|
|
369
|
-
|
|
370
|
-
|
|
371
|
+
if (prior)
|
|
372
|
+
await fs.promises.unlink(dst);
|
|
373
|
+
await seedInstallSafeNodeModules(src, dst);
|
|
371
374
|
linked.push(rel === "." ? "node_modules" : `${rel}/node_modules`);
|
|
372
375
|
}
|
|
373
376
|
catch (err) {
|
|
@@ -378,7 +381,7 @@ export async function ensureWorktreeNodeModules(workdir, repoPath, opts = {}) {
|
|
|
378
381
|
linked,
|
|
379
382
|
installed: false,
|
|
380
383
|
detail: linked.length
|
|
381
|
-
? `seeded ${linked.length} node_modules
|
|
384
|
+
? `seeded ${linked.length} install-safe node_modules dir(s) from warm clone`
|
|
382
385
|
: "worktree already provisioned; nothing to seed",
|
|
383
386
|
depsMissing: false,
|
|
384
387
|
};
|
|
@@ -429,7 +432,7 @@ export async function verifyWorktreeDepsFreshness(workdir, repoPath, opts = {})
|
|
|
429
432
|
`node_modules were symlinked from`;
|
|
430
433
|
const install = opts.install ?? defaultWorktreeInstall;
|
|
431
434
|
try {
|
|
432
|
-
await install(workdir);
|
|
435
|
+
await install(workdir); // writes the worktree only: the seed is a real dir (LANE-WARM-CLONE-…-1)
|
|
433
436
|
return {
|
|
434
437
|
fresh: true, lockfileHash, parentLockfileHash, installed: true, depsMissing: false,
|
|
435
438
|
detail: `${drift} — reinstalled in worktree`,
|
|
@@ -1981,6 +1984,15 @@ export function runTask(taskId, deps) {
|
|
|
1981
1984
|
* with block_reason `gate_tool_crashed:<gate>`, which is still fail-CLOSED
|
|
1982
1985
|
* because no PR is opened off a check that never ran.
|
|
1983
1986
|
*/
|
|
1987
|
+
// LANE-WARM-CLONE-NODE-MODULES-REWRITE-1 (AC3): a module-resolution gate
|
|
1988
|
+
// failure is a LANE fault (not a verdict on the diff) when the warm parent
|
|
1989
|
+
// clone's node_modules links are dangling. Null → keep the code verdict.
|
|
1990
|
+
const reclassifyDanglingParentDeps = async (fail) => {
|
|
1991
|
+
if (fail.gate === "deps" || fail.gate === "deps-stale")
|
|
1992
|
+
return null;
|
|
1993
|
+
const dangling = await findDanglingWarmCloneLinks(repoPath).catch(() => []);
|
|
1994
|
+
return classifyDanglingParentDeps(fail, repoPath, dangling, deps.session.runnerId);
|
|
1995
|
+
};
|
|
1984
1996
|
const handleGateToolCrash = async (result, crash, rework) => {
|
|
1985
1997
|
// Advisory probe: a GitHub hiccup must never be what decides this, so an
|
|
1986
1998
|
// unreadable probe degrades to "no PR" — and that route is `blocked`,
|
|
@@ -3426,12 +3438,18 @@ export function runTask(taskId, deps) {
|
|
|
3426
3438
|
// WORKTREE-STALE-DEPS-1: `deps-stale` is the sibling environment
|
|
3427
3439
|
// fault (deps WERE seeded, the merge above left them stale) — kept
|
|
3428
3440
|
// out of the generic `rework_gate_failed` bucket for the same reason.
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
|
|
3433
|
-
|
|
3434
|
-
|
|
3441
|
+
// LANE-WARM-CLONE-NODE-MODULES-REWRITE-1 (AC3): a dangling warm clone
|
|
3442
|
+
// is a lane fault here too — out of the `rework_gate_failed` bucket.
|
|
3443
|
+
const dangling = await reclassifyDanglingParentDeps(fail);
|
|
3444
|
+
const blockReason = dangling ? dangling.blockReason : gateFailureBlockReason(fail.gate);
|
|
3445
|
+
const errorClass = dangling
|
|
3446
|
+
? dangling.errorClass
|
|
3447
|
+
: fail.gate === "deps"
|
|
3448
|
+
? DEPS_MISSING_CLASSIFICATION
|
|
3449
|
+
: fail.gate === "deps-stale"
|
|
3450
|
+
? DEPS_STALE_CLASSIFICATION
|
|
3451
|
+
: "rework_gate_failed";
|
|
3452
|
+
const stderrTail = dangling ? dangling.notice : fail.outputTail;
|
|
3435
3453
|
await appendEvent(deps.supabase, taskId, "rework_halt", {
|
|
3436
3454
|
phase: "prepr_gate",
|
|
3437
3455
|
pr_number: reworkMeta.pr_number,
|
|
@@ -3446,7 +3464,7 @@ export function runTask(taskId, deps) {
|
|
|
3446
3464
|
// it TIMED OUT, so a timeout halt is distinguishable from a genuine
|
|
3447
3465
|
// assertion halt without hand-querying stderr_tail.
|
|
3448
3466
|
...gateFailureRecordFields(fail),
|
|
3449
|
-
stderr_tail:
|
|
3467
|
+
stderr_tail: stderrTail,
|
|
3450
3468
|
runner_id: deps.session.runnerId,
|
|
3451
3469
|
});
|
|
3452
3470
|
await emitGateTimeoutBreadcrumb(fail);
|
|
@@ -3459,7 +3477,7 @@ export function runTask(taskId, deps) {
|
|
|
3459
3477
|
error_class: errorClass,
|
|
3460
3478
|
block_reason: blockReason,
|
|
3461
3479
|
failed_gate: fail.gate,
|
|
3462
|
-
stderr_tail:
|
|
3480
|
+
stderr_tail: stderrTail,
|
|
3463
3481
|
});
|
|
3464
3482
|
await transitionBlocked(blockReason, {
|
|
3465
3483
|
phase: "prepr_gate",
|
|
@@ -3603,18 +3621,27 @@ export function runTask(taskId, deps) {
|
|
|
3603
3621
|
// a rework merge just left them stale — kept as its own class end-to-end
|
|
3604
3622
|
// so triage never conflates "no environment" with "stale environment".
|
|
3605
3623
|
const depsStale = fail.gate === "deps-stale";
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3613
|
-
|
|
3614
|
-
|
|
3615
|
-
|
|
3616
|
-
|
|
3617
|
-
|
|
3624
|
+
// LANE-WARM-CLONE-NODE-MODULES-REWRITE-1 (AC3): a module-resolution
|
|
3625
|
+
// failure over a DANGLING warm clone is a lane fault, parked (not a code
|
|
3626
|
+
// reject) so the sweep requeues it losslessly.
|
|
3627
|
+
const dangling = await reclassifyDanglingParentDeps(fail);
|
|
3628
|
+
const envFault = depsMissing || depsStale || dangling !== null;
|
|
3629
|
+
const blockReason = dangling ? dangling.blockReason : gateFailureBlockReason(fail.gate);
|
|
3630
|
+
const errorClass = dangling
|
|
3631
|
+
? dangling.errorClass
|
|
3632
|
+
: depsMissing
|
|
3633
|
+
? DEPS_MISSING_CLASSIFICATION
|
|
3634
|
+
: depsStale
|
|
3635
|
+
? DEPS_STALE_CLASSIFICATION
|
|
3636
|
+
: PREPR_GATE_FAILED_CLASSIFICATION;
|
|
3637
|
+
const stderrTail = dangling ? dangling.notice : fail.outputTail;
|
|
3638
|
+
const summary = dangling
|
|
3639
|
+
? `pre-PR ${fail.gate} gate could not run: the warm clone's node_modules dangle (${blockReason}) — lane fault, PR not opened`
|
|
3640
|
+
: depsMissing
|
|
3641
|
+
? `pre-PR gate could not run: worktree has no node_modules (${blockReason}) — PR not opened`
|
|
3642
|
+
: depsStale
|
|
3643
|
+
? `pre-PR gate could not run: worktree deps are stale vs the merged lockfile (${blockReason}) — PR not opened`
|
|
3644
|
+
: `pre-PR ${fail.gate} gate failed (${blockReason}, exit ${fail.exitCode ?? "signal"}) — PR not opened`;
|
|
3618
3645
|
await appendEvent(deps.supabase, taskId, "error", {
|
|
3619
3646
|
phase: "prepr_gate",
|
|
3620
3647
|
error_class: errorClass,
|
|
@@ -3626,7 +3653,7 @@ export function runTask(taskId, deps) {
|
|
|
3626
3653
|
// PREPR-GATE-TIMEOUT-VISIBILITY-1: same structured timeout/assertion
|
|
3627
3654
|
// fingerprint as the rework_halt path above.
|
|
3628
3655
|
...gateFailureRecordFields(fail),
|
|
3629
|
-
stderr_tail:
|
|
3656
|
+
stderr_tail: stderrTail,
|
|
3630
3657
|
runner_id: deps.session.runnerId,
|
|
3631
3658
|
});
|
|
3632
3659
|
// RUNNER-TEST-HANG-SLOT-LEAK-1: a wall-clock test-gate timeout gets its
|
|
@@ -3641,7 +3668,7 @@ export function runTask(taskId, deps) {
|
|
|
3641
3668
|
error_class: errorClass,
|
|
3642
3669
|
block_reason: blockReason,
|
|
3643
3670
|
failed_gate: fail.gate,
|
|
3644
|
-
stderr_tail:
|
|
3671
|
+
stderr_tail: stderrTail,
|
|
3645
3672
|
});
|
|
3646
3673
|
if (envFault) {
|
|
3647
3674
|
// Park, never fail — same reasoning as a crashed gate tool
|