@dev-loops/core 1.0.0-rc.4 → 1.0.0-rc.6
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/package.json +6 -1
- package/src/claude/hook-decisions.mjs +172 -5
- package/src/cli/primitives.mjs +21 -0
- package/src/config/config.mjs +83 -2
- package/src/config/extension-defaults.yaml +5 -0
- package/src/github/comment-id-guard.mjs +70 -0
- package/src/github/copilot-helpers.mjs +31 -0
- package/src/github/issue-ops.mjs +6 -0
- package/src/loop/agent-stall.mjs +194 -0
- package/src/loop/bash-command-classify.mjs +277 -0
- package/src/loop/cache-telemetry-evidence.mjs +437 -0
- package/src/loop/copilot-ci-status.mjs +18 -7
- package/src/loop/default-branch-guard.mjs +1 -1
- package/src/loop/gate-fanin.mjs +244 -0
- package/src/loop/handoff-envelope.mjs +28 -1
- package/src/loop/issue-refinement-artifact.mjs +154 -18
- package/src/loop/main-checkout-ff.mjs +39 -0
- package/src/loop/primer-evidence.mjs +375 -0
- package/src/loop/public-dev-loop-routing.mjs +12 -0
- package/src/loop/retrospective-checkpoint.mjs +77 -13
- package/src/loop/review-dispatch-plan.mjs +595 -0
- package/src/loop/review-lineage.mjs +588 -0
- package/src/loop/worktree-guard.mjs +80 -0
- package/src/projects/move-queue-item.mjs +37 -1
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { runChild as _runChild } from "../cli/primitives.mjs";
|
|
2
2
|
import { parseJsonText } from "../github/review-threads.mjs";
|
|
3
|
+
import { runPickupRefinementGate } from "../loop/issue-refinement-artifact.mjs";
|
|
4
|
+
import { loadStateColumnMap, LOGICAL_COLUMN } from "../loop/queue-board-sync.mjs";
|
|
3
5
|
import { resolveProjectSelector, findProject, parseItemRef } from "./resolve-project.mjs";
|
|
4
6
|
|
|
5
7
|
// ── Validation ───────────────────────────────────────────────────────────
|
|
@@ -252,6 +254,7 @@ function statusOf(node) {
|
|
|
252
254
|
function classifyExitCode(err) {
|
|
253
255
|
if (err.code === "INVALID_REPO" || err.code === "INVALID_PROJECT" || err.code === "INVALID_ITEM" ||
|
|
254
256
|
err.code === "INVALID_COLUMN" || err.code === "INVALID_ARGS") return 1;
|
|
257
|
+
if (err.code === "MISSING_REFINEMENT_ARTIFACT") return 4;
|
|
255
258
|
if (err.code === "PROJECT_NOT_FOUND" || err.code === "FIELD_NOT_FOUND" || err.code === "COLUMN_NOT_FOUND" ||
|
|
256
259
|
err.code === "ITEM_NOT_FOUND") return 3;
|
|
257
260
|
return 2;
|
|
@@ -259,7 +262,7 @@ function classifyExitCode(err) {
|
|
|
259
262
|
|
|
260
263
|
// ── Main logic ──────────────────────────────────────────────────────────
|
|
261
264
|
|
|
262
|
-
async function main(args, { env = process.env, runChild } = {}) {
|
|
265
|
+
async function main(args, { env = process.env, runChild, cwd = null } = {}) {
|
|
263
266
|
const child = runChild ?? _runChild;
|
|
264
267
|
const repo = validateRepo(args.repo);
|
|
265
268
|
const [owner, repoName] = repo.split("/");
|
|
@@ -365,6 +368,38 @@ async function main(args, { env = process.env, runChild } = {}) {
|
|
|
365
368
|
};
|
|
366
369
|
}
|
|
367
370
|
|
|
371
|
+
// 5b. QUEUE-ENQUEUE-REFINEMENT-GATE: moving an ISSUE into the pickup column
|
|
372
|
+
// must pass the same refinement gate `queue add` applies — a guard at one
|
|
373
|
+
// entry point but not its sibling is exactly the asymmetry this closes. Put
|
|
374
|
+
// here (in core, not the script wrapper) so every caller routing through core
|
|
375
|
+
// is covered — reconcile-queue.mjs included. reconcile is unaffected because
|
|
376
|
+
// it passes no cwd and never derives the pickup column. The column name is
|
|
377
|
+
// only derivable when cwd/config is supplied: an interactive `queue move` from
|
|
378
|
+
// a worktree passes cwd (gate fires), while headless callers (e.g.
|
|
379
|
+
// reconcile-queue.mjs) omit it and are unaffected — we simply never derive
|
|
380
|
+
// the column.
|
|
381
|
+
let refinement = null;
|
|
382
|
+
if (issueNumber !== null && typeof cwd === "string" && cwd.length > 0) {
|
|
383
|
+
const { columnNames, error: columnError } = loadStateColumnMap(cwd);
|
|
384
|
+
const pickupColumn = columnNames[LOGICAL_COLUMN.NEXT_UP];
|
|
385
|
+
if (pickupColumn && toColumn === pickupColumn) {
|
|
386
|
+
// Mirror queue add's fail-closed posture on a malformed `.devloops` when the
|
|
387
|
+
// interactive path supplied cwd AND the target is actually the pickup
|
|
388
|
+
// column: a config parse failure must never silently bypass the just-moved
|
|
389
|
+
// pickup refinement gate (the exact sibling asymmetry this issue closes).
|
|
390
|
+
// Scoped here (after the pickup-column guard) so an unrelated column move
|
|
391
|
+
// is not over-broadened into a hard CONFIG_ERROR failure.
|
|
392
|
+
if (columnError) {
|
|
393
|
+
throw Object.assign(
|
|
394
|
+
new Error(`could not resolve the pickup column (config read/parse error: ${columnError})`),
|
|
395
|
+
{ code: "CONFIG_ERROR" },
|
|
396
|
+
);
|
|
397
|
+
}
|
|
398
|
+
const decision = await runPickupRefinementGate({ issueNumber, repo, env, runChild: child, auto: false });
|
|
399
|
+
refinement = { refined: decision.action === "enqueue" };
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
368
403
|
// 6. Update Status via mutation
|
|
369
404
|
const updatePayload = await ghGraphql(UPDATE_ITEM_FIELD, {
|
|
370
405
|
projectId: project.id,
|
|
@@ -388,6 +423,7 @@ async function main(args, { env = process.env, runChild } = {}) {
|
|
|
388
423
|
newColumn: toColumn,
|
|
389
424
|
unchanged: false,
|
|
390
425
|
},
|
|
426
|
+
...(refinement ? { refinement } : {}),
|
|
391
427
|
};
|
|
392
428
|
}
|
|
393
429
|
|