chore(sf): autonomous docstring sweep — additional SF extension files
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
038938f2ac
commit
c6a7c7772d
20 changed files with 124 additions and 9 deletions
|
|
@ -81,6 +81,10 @@ export class ModelPolicyDispatchBlockedError extends Error {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Result of model selection and application for a unit dispatch.
|
||||
* Includes routing metadata and the applied model object.
|
||||
*/
|
||||
export interface ModelSelectionResult {
|
||||
/** Routing metadata for metrics recording */
|
||||
routing: { tier: string; modelDowngraded: boolean } | null;
|
||||
|
|
@ -241,6 +245,10 @@ function matchesBareModelId(candidateId: string, requestedId: string): boolean {
|
|||
return bareModelIdAliases(requestedId).has(candidateId.toLowerCase());
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve preferred model configuration for a unit type from preferences or dynamic routing.
|
||||
* Returns undefined if no explicit config and auto-mode is disabled or flat-rate provider detected.
|
||||
*/
|
||||
export function resolvePreferredModelConfig(
|
||||
unitType: string,
|
||||
autoModeStartModel: {
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ function saveCustomVerifyRetryCounts(s: AutoSession): void {
|
|||
return;
|
||||
}
|
||||
mkdirSync(customVerifyRetryStateDir(s), { recursive: true });
|
||||
writeFileSync(
|
||||
atomicWriteSync(
|
||||
filePath,
|
||||
JSON.stringify({
|
||||
counts: Object.fromEntries(retryCounts),
|
||||
|
|
|
|||
|
|
@ -135,6 +135,9 @@ function writeGateSnapshotPath(basePath: string = process.cwd()): string {
|
|||
return join(basePath, ".sf", "runtime", "write-gate-state.json");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the current in-memory write gate snapshot.
|
||||
*/
|
||||
function currentWriteGateSnapshot(): WriteGateSnapshot {
|
||||
return {
|
||||
verifiedDepthMilestones: [...verifiedDepthMilestones].sort(),
|
||||
|
|
@ -160,6 +163,9 @@ function persistWriteGateSnapshot(basePath: string = process.cwd()): void {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete the persisted write gate snapshot file if it exists.
|
||||
*/
|
||||
function clearPersistedWriteGateSnapshot(
|
||||
basePath: string = process.cwd(),
|
||||
): void {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ import { projectRoot } from "./commands/context.js";
|
|||
import { profileRepository } from "./repo-profiler.js";
|
||||
import { recordRepoProfile } from "./sf-db.js";
|
||||
|
||||
/**
|
||||
* Format a repo profile summary for user notification.
|
||||
*/
|
||||
function formatProfileSummary(
|
||||
profile: ReturnType<typeof profileRepository>,
|
||||
): string {
|
||||
|
|
|
|||
|
|
@ -24,6 +24,9 @@ import { sfRoot } from "./paths.js";
|
|||
|
||||
// ─── Types ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Activity log entry metadata parsed from filename.
|
||||
*/
|
||||
interface LogEntry {
|
||||
seq: number;
|
||||
filename: string;
|
||||
|
|
@ -33,6 +36,9 @@ interface LogEntry {
|
|||
mtime: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug log entry metadata.
|
||||
*/
|
||||
interface DebugLogEntry {
|
||||
filename: string;
|
||||
size: number;
|
||||
|
|
@ -41,14 +47,23 @@ interface DebugLogEntry {
|
|||
|
||||
// ─── Helpers ────────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Get the activity logs directory path.
|
||||
*/
|
||||
function activityDir(basePath: string): string {
|
||||
return join(sfRoot(basePath), "activity");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the debug logs directory path.
|
||||
*/
|
||||
function debugDir(basePath: string): string {
|
||||
return join(sfRoot(basePath), "debug");
|
||||
}
|
||||
|
||||
/**
|
||||
* List all activity logs with parsed metadata from filenames.
|
||||
*/
|
||||
function listActivityLogs(basePath: string): LogEntry[] {
|
||||
const dir = activityDir(basePath);
|
||||
if (!existsSync(dir)) return [];
|
||||
|
|
|
|||
|
|
@ -11,6 +11,9 @@ import { getActiveMemoriesRanked, type Memory } from "./memory-store.js";
|
|||
export const DEFAULT_SNAPSHOT_BYTES = 2048;
|
||||
export const SNAPSHOT_FILENAME = "last-snapshot.md";
|
||||
|
||||
/**
|
||||
* Input sources for building a compaction snapshot: memories, exec history, and active context.
|
||||
*/
|
||||
export interface SnapshotSources {
|
||||
memories: Memory[];
|
||||
execHistory: ExecHistoryEntry[];
|
||||
|
|
@ -19,6 +22,9 @@ export interface SnapshotSources {
|
|||
activeContext?: string | null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Options for building a snapshot (byte/count caps).
|
||||
*/
|
||||
export interface BuildSnapshotOptions {
|
||||
/** Hard cap in bytes (UTF-8). Default 2048. */
|
||||
maxBytes?: number;
|
||||
|
|
|
|||
|
|
@ -16,6 +16,11 @@ const SLICE_DISPATCH_TYPES = new Set([
|
|||
"complete-slice",
|
||||
]);
|
||||
|
||||
/**
|
||||
* Check if a slice/task dispatch should be blocked by incomplete prior slices.
|
||||
* Returns error message if blocked, null if dispatch is safe.
|
||||
* Respects milestone locking (SF_MILESTONE_LOCK) for parallel worker isolation.
|
||||
*/
|
||||
export function getPriorSliceCompletionBlocker(
|
||||
base: string,
|
||||
_mainBranch: string,
|
||||
|
|
|
|||
|
|
@ -391,7 +391,6 @@ export async function checkRuntimeHealth(
|
|||
// templates SF currently ships. Non-fatal — automatic sync runs in
|
||||
// ensureAgenticDocsScaffold; this check is the user-visible signal.
|
||||
try {
|
||||
const { detectScaffoldDrift } = await import("./scaffold-drift.js");
|
||||
const report = detectScaffoldDrift(basePath);
|
||||
const c = report.countsByBucket;
|
||||
// Only emit a finding when something is actionable. `customized` and
|
||||
|
|
|
|||
|
|
@ -385,6 +385,20 @@ function detectCircularDependencies(slices: RoadmapSliceEntry[]): string[][] {
|
|||
}
|
||||
|
||||
// ── Helper: doctor run history ──────────────────────────────────────────────
|
||||
/**
|
||||
* Single doctor run history entry for tracking past results and fixes.
|
||||
*
|
||||
* @property ts — ISO timestamp of the run
|
||||
* @property ok — true if no errors were found
|
||||
* @property errors — count of error-severity issues
|
||||
* @property warnings — count of warning-severity issues
|
||||
* @property fixes — count of fixes applied
|
||||
* @property codes — unique issue codes found
|
||||
* @property issues — detailed issue messages (Phase 2+)
|
||||
* @property fixDescriptions — descriptions of fixes applied (Phase 2+)
|
||||
* @property scope — milestone/slice scope the run was scoped to (e.g., "M001/S02")
|
||||
* @property summary — human-readable one-line summary
|
||||
*/
|
||||
export interface DoctorHistoryEntry {
|
||||
ts: string;
|
||||
ok: boolean;
|
||||
|
|
|
|||
|
|
@ -99,6 +99,9 @@ export function getExecuteTaskInstructionConflict(
|
|||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark a task skipped due to instruction conflict and log the event.
|
||||
*/
|
||||
export async function skipExecuteTaskForInstructionConflict(
|
||||
basePath: string,
|
||||
mid: string,
|
||||
|
|
|
|||
|
|
@ -179,6 +179,7 @@ export const GATE_REGISTRY = {
|
|||
},
|
||||
} as const satisfies Record<GateId, GateDefinition>;
|
||||
|
||||
/** Type of the GATE_REGISTRY constant. */
|
||||
export type GateRegistry = typeof GATE_REGISTRY;
|
||||
|
||||
/** Stable ordered lists per owner turn — iteration order matches declaration. */
|
||||
|
|
@ -186,7 +187,9 @@ const ORDERED_GATES: readonly GateDefinition[] = Object.values(
|
|||
GATE_REGISTRY,
|
||||
) as readonly GateDefinition[];
|
||||
|
||||
/** Return every gate owned by a turn, in stable declaration order. */
|
||||
/**
|
||||
* Return every gate owned by a turn, in stable declaration order.
|
||||
*/
|
||||
export function getGatesForTurn(turn: OwnerTurn): GateDefinition[] {
|
||||
return ORDERED_GATES.filter((g) => g.ownerTurn === turn);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,15 +109,19 @@ export interface GitPreferences {
|
|||
milestone_resquash?: boolean;
|
||||
}
|
||||
|
||||
/** Regex for valid git branch names (alphanumeric, hyphens, underscores, slashes). */
|
||||
export const VALID_BRANCH_NAME = /^[a-zA-Z0-9_\-/.]+$/;
|
||||
|
||||
/** Options for git commit operations. */
|
||||
export interface CommitOptions {
|
||||
message: string;
|
||||
allowEmpty?: boolean;
|
||||
}
|
||||
|
||||
/** Mode for turn-level git action (commit, snapshot, or status-only check). */
|
||||
export type TurnGitActionMode = "commit" | "snapshot" | "status-only";
|
||||
|
||||
/** Result from a turn-level git action execution. */
|
||||
export interface TurnGitActionResult {
|
||||
action: TurnGitActionMode;
|
||||
status: "ok" | "failed";
|
||||
|
|
|
|||
|
|
@ -41,8 +41,8 @@ function formatCost(n: number): string {
|
|||
}
|
||||
|
||||
/**
|
||||
* Format a Unix epoch (seconds) as a human-readable relative time string.
|
||||
* Returns "just now" for <1m, "Xm ago" for <1h, "Xh ago" for <24h, "Xd ago" otherwise.
|
||||
* Format Unix epoch (seconds) as human-readable relative time.
|
||||
* Returns "just now", "Xm ago", "Xh ago", or "Xd ago".
|
||||
*/
|
||||
export function formatRelativeTime(epochSeconds: number): string {
|
||||
const diffSeconds = Math.floor(Date.now() / 1000) - epochSeconds;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,10 @@ import { formattedShortcutPair } from "./shortcut-defs.js";
|
|||
|
||||
// ─── Pure rendering ──<E29480><E29480><EFBFBD>────────────────────────<E29480><E29480><EFBFBD>─────────────────────────
|
||||
|
||||
/**
|
||||
* Build the notification widget UI lines. Returns empty array if no unread
|
||||
* notifications; otherwise shows unread count and keyboard shortcut hint.
|
||||
*/
|
||||
export function buildNotificationWidgetLines(): string[] {
|
||||
const unread = getUnreadCount();
|
||||
if (unread === 0) return [];
|
||||
|
|
|
|||
|
|
@ -10,7 +10,15 @@ import {
|
|||
import { loadEffectiveSFPreferences } from "./preferences.js";
|
||||
import type { NotificationPreferences } from "./types.js";
|
||||
|
||||
/**
|
||||
* Notification urgency level, controls icon, sound, and visual prominence.
|
||||
*/
|
||||
export type NotifyLevel = "info" | "success" | "warning" | "error";
|
||||
|
||||
/**
|
||||
* Classification of notification event type, used to gate desktop notification
|
||||
* delivery via user preferences.
|
||||
*/
|
||||
export type NotificationKind =
|
||||
| "complete"
|
||||
| "error"
|
||||
|
|
@ -18,6 +26,10 @@ export type NotificationKind =
|
|||
| "milestone"
|
||||
| "attention";
|
||||
|
||||
/**
|
||||
* Platform-specific command for delivering a desktop notification.
|
||||
* Specifies the executable and its arguments.
|
||||
*/
|
||||
interface NotificationCommand {
|
||||
file: string;
|
||||
args: string[];
|
||||
|
|
|
|||
|
|
@ -328,13 +328,30 @@ export function resolveModelWithFallbacksForUnit(
|
|||
case "plan-milestone":
|
||||
case "roadmap-meeting":
|
||||
case "plan-slice":
|
||||
case "refine-slice":
|
||||
case "replan-slice":
|
||||
phaseConfig = m.planning;
|
||||
break;
|
||||
case "discuss-milestone":
|
||||
case "discuss-slice":
|
||||
// Deep-mode project-level discussion units route to the same model
|
||||
// bucket as milestone-level discussion (interactive interview style).
|
||||
case "discuss-project":
|
||||
case "discuss-requirements":
|
||||
// Workflow preferences and research-decision are tiny ask_user_questions
|
||||
// style units; they share the discuss bucket because they are
|
||||
// conversational rather than research/execution. Falling back to planning
|
||||
// when no `discuss` bucket is set keeps parity with the milestone units.
|
||||
case "workflow-preferences":
|
||||
case "research-decision":
|
||||
phaseConfig = m.discuss ?? m.planning;
|
||||
break;
|
||||
// Deep-mode project research orchestrator. Reads PROJECT.md / REQUIREMENTS.md
|
||||
// and fans out research subagents. Routes to the research bucket so it
|
||||
// gets the research-tier model when one is configured.
|
||||
case "research-project":
|
||||
phaseConfig = m.research;
|
||||
break;
|
||||
case "execute-task":
|
||||
case "reactive-execute":
|
||||
phaseConfig = m.execution;
|
||||
|
|
|
|||
|
|
@ -129,8 +129,14 @@ export function resolveSkillReference(
|
|||
}
|
||||
|
||||
/**
|
||||
* Resolve all skill references in a preferences object.
|
||||
* Caches resolution per reference string to avoid redundant filesystem scans.
|
||||
* Resolve all skill references across a preferences object.
|
||||
*
|
||||
* Walks all_use_skills, prefer_skills, avoid_skills, and skill rules;
|
||||
* caches resolution per reference to avoid redundant directory scans.
|
||||
*
|
||||
* @param preferences - Preferences object with skill references.
|
||||
* @param cwd - Current working directory for project-relative search.
|
||||
* @returns Map of resolutions and list of unresolved references.
|
||||
*/
|
||||
export function resolveAllSkillReferences(
|
||||
preferences: SFPreferences,
|
||||
|
|
|
|||
|
|
@ -52,7 +52,9 @@ interface TaskPlanInput {
|
|||
// Decisions
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
/** Compact format for a single decision record (pipe-separated, no padding). */
|
||||
/**
|
||||
* Format a single decision as pipe-separated compact notation.
|
||||
*/
|
||||
export function formatDecisionCompact(decision: DecisionInput): string {
|
||||
return [
|
||||
decision.id,
|
||||
|
|
@ -66,7 +68,9 @@ export function formatDecisionCompact(decision: DecisionInput): string {
|
|||
].join(" | ");
|
||||
}
|
||||
|
||||
/** Format multiple decisions in compact notation with a Fields header. */
|
||||
/**
|
||||
* Format multiple decisions in compact notation with Fields header.
|
||||
*/
|
||||
export function formatDecisionsCompact(decisions: DecisionInput[]): string {
|
||||
if (decisions.length === 0) {
|
||||
return "# Decisions (compact)\n(none)";
|
||||
|
|
|
|||
|
|
@ -1234,6 +1234,9 @@ export function renderCapturesView(
|
|||
|
||||
// ─── Health View ─────────────────────────────────────────────────────────────
|
||||
|
||||
/**
|
||||
* Render system health: budget, pressure, routing, providers, progress score, doctor history.
|
||||
*/
|
||||
export function renderHealthView(
|
||||
data: VisualizerData,
|
||||
th: Theme,
|
||||
|
|
|
|||
|
|
@ -46,7 +46,10 @@ function baseEntry(
|
|||
// Closed sets so typos at call sites are rejected at compile time and can't
|
||||
// silently fragment the telemetry buckets produced by summarizeWorktreeTelemetry.
|
||||
|
||||
/** Reason a worktree was created or entered (create-milestone | enter-milestone). */
|
||||
export type WorktreeCreatedReason = "create-milestone" | "enter-milestone";
|
||||
|
||||
/** Reason auto-mode exited (pause, stop, blocked, merge-conflict, merge-failed, etc.). */
|
||||
export type AutoExitReason =
|
||||
| "pause"
|
||||
| "stop"
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue