refactor: adopt parseUnitId utility across all auto-* modules
Replace manual unitId.split("/") calls with the canonical parseUnitId()
utility from unit-id.ts. This eliminates ad-hoc array indexing patterns
(parts[0]!, parts[1], parts[2]) in favor of named destructuring
({ milestone, slice, task }), improving readability and consistency.
Files modified:
- auto-post-unit.ts (5 occurrences)
- auto-artifact-paths.ts (2 occurrences)
- auto-dashboard.ts (1 occurrence)
- auto-verification.ts (1 occurrence)
- auto-start.ts (1 occurrence)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
ef5006e16d
commit
15030ce97d
5 changed files with 30 additions and 43 deletions
|
|
@ -13,6 +13,7 @@ import {
|
|||
buildSliceFileName,
|
||||
buildTaskFileName,
|
||||
} from "./paths.js";
|
||||
import { parseUnitId } from "./unit-id.js";
|
||||
import { join } from "node:path";
|
||||
|
||||
/**
|
||||
|
|
@ -23,9 +24,7 @@ export function resolveExpectedArtifactPath(
|
|||
unitId: string,
|
||||
base: string,
|
||||
): string | null {
|
||||
const parts = unitId.split("/");
|
||||
const mid = parts[0]!;
|
||||
const sid = parts[1];
|
||||
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
||||
switch (unitType) {
|
||||
case "discuss-milestone": {
|
||||
const dir = resolveMilestonePath(base, mid);
|
||||
|
|
@ -56,7 +55,6 @@ export function resolveExpectedArtifactPath(
|
|||
return dir ? join(dir, buildSliceFileName(sid!, "UAT")) : null;
|
||||
}
|
||||
case "execute-task": {
|
||||
const tid = parts[2];
|
||||
const dir = resolveSlicePath(base, mid, sid!);
|
||||
return dir && tid
|
||||
? join(dir, "tasks", buildTaskFileName(tid, "SUMMARY"))
|
||||
|
|
@ -93,38 +91,35 @@ export function diagnoseExpectedArtifact(
|
|||
unitId: string,
|
||||
base: string,
|
||||
): string | null {
|
||||
const parts = unitId.split("/");
|
||||
const mid = parts[0];
|
||||
const sid = parts[1];
|
||||
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
||||
switch (unitType) {
|
||||
case "discuss-milestone":
|
||||
return `${relMilestoneFile(base, mid!, "CONTEXT")} (milestone context from discussion)`;
|
||||
return `${relMilestoneFile(base, mid, "CONTEXT")} (milestone context from discussion)`;
|
||||
case "research-milestone":
|
||||
return `${relMilestoneFile(base, mid!, "RESEARCH")} (milestone research)`;
|
||||
return `${relMilestoneFile(base, mid, "RESEARCH")} (milestone research)`;
|
||||
case "plan-milestone":
|
||||
return `${relMilestoneFile(base, mid!, "ROADMAP")} (milestone roadmap)`;
|
||||
return `${relMilestoneFile(base, mid, "ROADMAP")} (milestone roadmap)`;
|
||||
case "research-slice":
|
||||
return `${relSliceFile(base, mid!, sid!, "RESEARCH")} (slice research)`;
|
||||
return `${relSliceFile(base, mid, sid!, "RESEARCH")} (slice research)`;
|
||||
case "plan-slice":
|
||||
return `${relSliceFile(base, mid!, sid!, "PLAN")} (slice plan)`;
|
||||
return `${relSliceFile(base, mid, sid!, "PLAN")} (slice plan)`;
|
||||
case "execute-task": {
|
||||
const tid = parts[2];
|
||||
return `Task ${tid} marked [x] in ${relSliceFile(base, mid!, sid!, "PLAN")} + summary written`;
|
||||
return `Task ${tid} marked [x] in ${relSliceFile(base, mid, sid!, "PLAN")} + summary written`;
|
||||
}
|
||||
case "complete-slice":
|
||||
return `Slice ${sid} marked [x] in ${relMilestoneFile(base, mid!, "ROADMAP")} + summary + UAT written`;
|
||||
return `Slice ${sid} marked [x] in ${relMilestoneFile(base, mid, "ROADMAP")} + summary + UAT written`;
|
||||
case "replan-slice":
|
||||
return `${relSliceFile(base, mid!, sid!, "REPLAN")} + updated ${relSliceFile(base, mid!, sid!, "PLAN")}`;
|
||||
return `${relSliceFile(base, mid, sid!, "REPLAN")} + updated ${relSliceFile(base, mid, sid!, "PLAN")}`;
|
||||
case "rewrite-docs":
|
||||
return "Active overrides resolved in .gsd/OVERRIDES.md + plan documents updated";
|
||||
case "reassess-roadmap":
|
||||
return `${relSliceFile(base, mid!, sid!, "ASSESSMENT")} (roadmap reassessment)`;
|
||||
return `${relSliceFile(base, mid, sid!, "ASSESSMENT")} (roadmap reassessment)`;
|
||||
case "run-uat":
|
||||
return `${relSliceFile(base, mid!, sid!, "UAT")} (UAT result)`;
|
||||
return `${relSliceFile(base, mid, sid!, "UAT")} (UAT result)`;
|
||||
case "validate-milestone":
|
||||
return `${relMilestoneFile(base, mid!, "VALIDATION")} (milestone validation report)`;
|
||||
return `${relMilestoneFile(base, mid, "VALIDATION")} (milestone validation report)`;
|
||||
case "complete-milestone":
|
||||
return `${relMilestoneFile(base, mid!, "SUMMARY")} (milestone summary)`;
|
||||
return `${relMilestoneFile(base, mid, "SUMMARY")} (milestone summary)`;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import { computeProgressScore } from "./progress-score.js";
|
|||
import { getActiveWorktreeName } from "./worktree-command.js";
|
||||
import { loadEffectiveGSDPreferences, getGlobalGSDPreferencesPath } from "./preferences.js";
|
||||
import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.js";
|
||||
import { parseUnitId } from "./unit-id.js";
|
||||
|
||||
// ─── UAT Slice Extraction ─────────────────────────────────────────────────────
|
||||
|
||||
|
|
@ -33,8 +34,8 @@ import { resolveServiceTierIcon, getEffectiveServiceTier } from "./service-tier.
|
|||
* Returns null if the format doesn't match.
|
||||
*/
|
||||
export function extractUatSliceId(unitId: string): string | null {
|
||||
const parts = unitId.split("/");
|
||||
if (parts.length >= 2 && parts[1]!.startsWith("S")) return parts[1]!;
|
||||
const { slice } = parseUnitId(unitId);
|
||||
if (slice?.startsWith("S")) return slice;
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import {
|
|||
buildTaskFileName,
|
||||
} from "./paths.js";
|
||||
import { invalidateAllCaches } from "./cache.js";
|
||||
import { parseUnitId } from "./unit-id.js";
|
||||
import { closeoutUnit, type CloseoutOptions } from "./auto-unit-closeout.js";
|
||||
import {
|
||||
autoCommitCurrentBranch,
|
||||
|
|
@ -91,11 +92,10 @@ export function detectRogueFileWrites(
|
|||
): RogueFileWrite[] {
|
||||
if (!isDbAvailable()) return [];
|
||||
|
||||
const parts = unitId.split("/");
|
||||
const { milestone: mid, slice: sid, task: tid } = parseUnitId(unitId);
|
||||
const rogues: RogueFileWrite[] = [];
|
||||
|
||||
if (unitType === "execute-task") {
|
||||
const [mid, sid, tid] = parts;
|
||||
if (!mid || !sid || !tid) return [];
|
||||
|
||||
const summaryPath = resolveTaskFile(basePath, mid, sid, tid, "SUMMARY");
|
||||
|
|
@ -106,7 +106,6 @@ export function detectRogueFileWrites(
|
|||
rogues.push({ path: summaryPath, unitType, unitId });
|
||||
}
|
||||
} else if (unitType === "complete-slice") {
|
||||
const [mid, sid] = parts;
|
||||
if (!mid || !sid) return [];
|
||||
|
||||
const summaryPath = resolveSliceFile(basePath, mid, sid, "SUMMARY");
|
||||
|
|
@ -117,7 +116,6 @@ export function detectRogueFileWrites(
|
|||
rogues.push({ path: summaryPath, unitType, unitId });
|
||||
}
|
||||
} else if (unitType === "plan-milestone") {
|
||||
const [mid] = parts;
|
||||
if (!mid) return [];
|
||||
|
||||
const roadmapPath = resolveMilestoneFile(basePath, mid, "ROADMAP");
|
||||
|
|
@ -135,7 +133,6 @@ export function detectRogueFileWrites(
|
|||
rogues.push({ path: roadmapPath, unitType, unitId });
|
||||
}
|
||||
} else if (unitType === "plan-slice" || unitType === "replan-slice") {
|
||||
const [mid, sid] = parts;
|
||||
if (!mid || !sid) return [];
|
||||
|
||||
const planPath = resolveSliceFile(basePath, mid, sid, "PLAN");
|
||||
|
|
@ -159,7 +156,6 @@ export function detectRogueFileWrites(
|
|||
rogues.push({ path: replanPath, unitType, unitId });
|
||||
}
|
||||
} else if (unitType === "reassess-roadmap") {
|
||||
const [mid, sid] = parts;
|
||||
if (!mid || !sid) return [];
|
||||
|
||||
const assessPath = resolveSliceFile(basePath, mid, sid, "ASSESSMENT");
|
||||
|
|
@ -176,7 +172,6 @@ export function detectRogueFileWrites(
|
|||
}
|
||||
}
|
||||
} else if (unitType === "plan-task") {
|
||||
const [mid, sid, tid] = parts;
|
||||
if (!mid || !sid || !tid) return [];
|
||||
|
||||
const taskPlanPath = resolveTaskFile(basePath, mid, sid, tid, "PLAN");
|
||||
|
|
@ -249,8 +244,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|||
let taskContext: TaskCommitContext | undefined;
|
||||
|
||||
if (s.currentUnit.type === "execute-task") {
|
||||
const parts = s.currentUnit.id.split("/");
|
||||
const [mid, sid, tid] = parts;
|
||||
const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
|
||||
if (mid && sid && tid) {
|
||||
const summaryPath = resolveTaskFile(s.basePath, mid, sid, tid, "SUMMARY");
|
||||
if (summaryPath) {
|
||||
|
|
@ -354,8 +348,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|||
// Reactive state cleanup on slice completion
|
||||
if (s.currentUnit.type === "complete-slice") {
|
||||
try {
|
||||
const parts = s.currentUnit.id.split("/");
|
||||
const [mid, sid] = parts;
|
||||
const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
|
||||
if (mid && sid) {
|
||||
const { clearReactiveState } = await import("./reactive-graph.js");
|
||||
clearReactiveState(s.basePath, mid, sid);
|
||||
|
|
@ -440,8 +433,7 @@ export async function postUnitPreVerification(pctx: PostUnitContext, opts?: PreV
|
|||
// from DB data before giving up (e.g. research-slice produces PLAN from engine).
|
||||
if (!triggerArtifactVerified) {
|
||||
try {
|
||||
const parts = s.currentUnit.id.split("/");
|
||||
const [mid, sid] = parts;
|
||||
const { milestone: mid, slice: sid } = parseUnitId(s.currentUnit.id);
|
||||
if (mid && sid) {
|
||||
const regenerated = regenerateIfMissing(s.basePath, mid, sid, "PLAN");
|
||||
if (regenerated) {
|
||||
|
|
@ -541,8 +533,7 @@ export async function postUnitPostVerification(pctx: PostUnitContext): Promise<"
|
|||
|
||||
// ── State reset: undo the completion so deriveState re-derives the unit ──
|
||||
try {
|
||||
const parts = trigger.unitId.split("/");
|
||||
const [mid, sid, tid] = parts;
|
||||
const { milestone: mid, slice: sid, task: tid } = parseUnitId(trigger.unitId);
|
||||
|
||||
// 1. Reset task status in DB and re-render plan checkboxes
|
||||
if (mid && sid && tid) {
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ import {
|
|||
isDebugEnabled,
|
||||
getDebugLogPath,
|
||||
} from "./debug-logger.js";
|
||||
import { parseUnitId } from "./unit-id.js";
|
||||
import type { AutoSession } from "./auto/session.js";
|
||||
import {
|
||||
existsSync,
|
||||
|
|
@ -200,7 +201,7 @@ export async function bootstrapAutoSession(
|
|||
);
|
||||
return releaseLockAndReturn();
|
||||
}
|
||||
const recoveredMid = crashLock.unitId.split("/")[0];
|
||||
const recoveredMid = parseUnitId(crashLock.unitId).milestone;
|
||||
const milestoneAlreadyComplete = recoveredMid
|
||||
? !!resolveMilestoneFile(base, recoveredMid, "SUMMARY")
|
||||
: false;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
import type { ExtensionContext, ExtensionAPI } from "@gsd/pi-coding-agent";
|
||||
import { resolveSliceFile, resolveSlicePath } from "./paths.js";
|
||||
import { parseUnitId } from "./unit-id.js";
|
||||
import { isDbAvailable, getTask } from "./gsd-db.js";
|
||||
import { loadEffectiveGSDPreferences } from "./preferences.js";
|
||||
import {
|
||||
|
|
@ -60,10 +61,9 @@ export async function runPostUnitVerification(
|
|||
const prefs = effectivePrefs?.preferences;
|
||||
|
||||
// Read task plan verify field
|
||||
const parts = s.currentUnit.id.split("/");
|
||||
const { milestone: mid, slice: sid, task: tid } = parseUnitId(s.currentUnit.id);
|
||||
let taskPlanVerify: string | undefined;
|
||||
if (parts.length >= 3) {
|
||||
const [mid, sid, tid] = parts;
|
||||
if (mid && sid && tid) {
|
||||
if (isDbAvailable()) {
|
||||
taskPlanVerify = getTask(mid, sid, tid)?.verify;
|
||||
}
|
||||
|
|
@ -141,9 +141,8 @@ export async function runPostUnitVerification(
|
|||
|
||||
// Write verification evidence JSON
|
||||
const attempt = s.verificationRetryCount.get(s.currentUnit.id) ?? 0;
|
||||
if (parts.length >= 3) {
|
||||
if (mid && sid && tid) {
|
||||
try {
|
||||
const [mid, sid, tid] = parts;
|
||||
const sDir = resolveSlicePath(s.basePath, mid, sid);
|
||||
if (sDir) {
|
||||
const tasksDir = join(sDir, "tasks");
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue