chore(sf): minor sweep — gate-registry dedup, token-counter, worktree-health

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Mikael Hugo 2026-05-02 02:18:03 +02:00
parent 86026c9e4f
commit abb3d76ffa
8 changed files with 26 additions and 7 deletions

View file

@ -1681,9 +1681,9 @@ async function runHeadlessOnce(
: exitCode === EXIT_CANCELLED
? "cancelled"
: exitCode === EXIT_ERROR
? totalEvents === 0
? "error"
: "timeout"
? timedOut
? "timeout"
: "error"
: "complete";
process.stderr.write(`[headless] Status: ${status}\n`);

View file

@ -70,7 +70,7 @@ import { recordSelfFeedback } from "./self-feedback.js";
// crossReferenceEvidence available for future use when verification_evidence is stored in DB
// import { crossReferenceEvidence, type ClaimedEvidence } from "./safety/evidence-cross-ref.js";
import { validateContent } from "./safety/content-validator.js";
import { getEvidence } from "./safety/evidence-collector.js";
import { clearEvidenceFromDisk, getEvidence } from "./safety/evidence-collector.js";
import { validateFileChanges } from "./safety/file-change-validator.js";
import { resolveSafetyHarnessConfig } from "./safety/safety-harness.js";
import { consumeSignal } from "./session-status-io.js";

View file

@ -183,7 +183,14 @@ export const GATE_REGISTRY = {
/** Type of the GATE_REGISTRY constant. */
export type GateRegistry = typeof GATE_REGISTRY;
/** Stable ordered lists per owner turn — iteration order matches declaration. */
/**
* Stable ordered lists per owner turn iteration order matches declaration.
*
* NOTE: Object.values() returns properties in insertion-order per the ES2020
* specification (§9.1.12). The gate execution order is therefore determined
* by the key-declaration order in GATE_REGISTRY above. Add new gates at the
* correct position in that object literal do NOT rely on alphabetical sort.
*/
const ORDERED_GATES: readonly GateDefinition[] = Object.values(
GATE_REGISTRY,
) as readonly GateDefinition[];

View file

@ -27,6 +27,9 @@ import type { SFPreferences } from "./preferences-types.js";
*/
export const CURRENT_PREFERENCES_SCHEMA_VERSION = 1;
/**
* A schema migration that transforms preferences from one version to the next.
*/
export interface Migration {
/** Schema version this migration upgrades from. */
from: number;

View file

@ -219,7 +219,9 @@ export function detectScaffoldDrift(basePath: string): ScaffoldDriftReport {
} else {
// Stamped version equals (or is somehow ahead of) shipped version
// and content matches — nothing to do. Bucket as `customized` per
// the spec ("already current").
// the spec ("already current"). NOTE: this bucket includes both
// unedited pending files (hash matches) and user-edited files;
// use hashDrifted flag to distinguish (false = no user edits).
items.push({
path: file.path,
template: file.path,

View file

@ -161,6 +161,9 @@ async function buildGoogleGeminiCliServer(apiKeyRaw: string) {
);
}
/**
* Type guard for Google Gemini token counting payload.
*/
export function isGoogleGeminiCountablePayload(
payload: unknown,
): payload is CountTokensParameters {

View file

@ -68,6 +68,10 @@ export interface TemplateMatch {
matchedTrigger?: string;
}
/**
* Scaffold data for a milestone slice generated from a template.
* Contains slice ID, title, risk, and planning details.
*/
export interface MilestoneTemplateSliceScaffold {
sliceId: string;
title: string;

View file

@ -7,7 +7,7 @@
* Only inspects worktrees under .sf/worktrees/ SF owns what SF creates.
*/
import { existsSync } from "node:fs";
import { existsSync, lstatSync } from "node:fs";
import {
nativeDetectMainBranch,
nativeHasChanges,