refactor: replace all inline error message ternaries with getErrorMessage()
Eliminates ~120 repetitions of `err instanceof Error ? err.message : String(err)` across the entire extension source tree. All callers now import and use `getErrorMessage` from the canonical `./error-utils.js`. Files updated (56 files): - auto.js, auto-worktree.js, auto-recovery.js, auto-dashboard.js, auto-timers.js - auto-prompts.js, auto-start.js, auto-post-unit.js, auto-model-selection.js - auto/phases.js, auto/loop.js, auto/infra-errors.js - autonomous-solver-eval.js, bootstrap/agent-end-recovery.js, bootstrap/db-tools.js - bootstrap/exec-tools.js, bootstrap/journal-tools.js, bootstrap/register-extension.js - bootstrap/register-hooks.js, canonical-milestone-plan.js, changelog.js - clean-root-preflight.js, code-intelligence.js, commands-add-tests.js - commands-debug.js, commands-eval-review.js, commands-handlers.js - commands-maintenance.js, commands-pr-branch.js, commands-scan.js, commands-ship.js - commands-todo.js, commands-worktree.js, definition-io.js, doctor.js - doctor-config-checks.js, doctor-engine-checks.js, ecosystem/loader.js - eval-review-schema.js, exec-sandbox.js, execution-instruction-guard.js - graph-context.js, hook-emitter.js, index.js, learning/runtime.js - lifecycle-hooks.js, onboarding-state.js, orphan-worktree-sweep.js - planning-depth.js, quick.js, scaffold-keeper.js, sf-db/sf-db-core.js - slice-cadence.js, sm-client.js, spec-projections.js, subagent/background-jobs.js - subagent/isolation.js, sync-scheduler.js, tools/exec-tool.js - tools/sift-search-tool.js, tools/workflow-tool-executors.js, ui/index.js - uok/a2a-agent-server.js, uok/auto-dispatch.js, uok/auto-unit-closeout.js - uok/auto-verification.js, uok/chaos-monkey.js, uok/gate-runner.js - vault-resolver.js, workflow-install.js, workflow-plugins.js, worktree-manager.js - worktree-resolver.js Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
parent
8a7f6de782
commit
04322f110a
74 changed files with 333 additions and 262 deletions
|
|
@ -348,7 +348,7 @@ export function updateSliceProgressCache(_base, mid, activeSid) {
|
|||
// Non-fatal — just omit task count
|
||||
logWarning(
|
||||
"dashboard",
|
||||
`operation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`operation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -363,7 +363,7 @@ export function updateSliceProgressCache(_base, mid, activeSid) {
|
|||
// Non-fatal — widget just won't show progress bar
|
||||
logWarning(
|
||||
"dashboard",
|
||||
`operation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`operation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -397,7 +397,7 @@ function refreshLastCommit(basePath) {
|
|||
// Non-fatal — just skip last commit display
|
||||
logWarning(
|
||||
"dashboard",
|
||||
`operation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`operation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -521,7 +521,7 @@ function persistWidgetMode(
|
|||
/* non-fatal — mode still set in memory */
|
||||
logWarning(
|
||||
"dashboard",
|
||||
`file write failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`file write failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -588,7 +588,7 @@ export function updateProgressWidget(
|
|||
/* not in git repo */
|
||||
logWarning(
|
||||
"dashboard",
|
||||
`git branch detection failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git branch detection failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Cache short pwd (last 2 path segments only) + worktree/branch info
|
||||
|
|
@ -632,7 +632,7 @@ export function updateProgressWidget(
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"dashboard",
|
||||
`RTK savings lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`RTK savings lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
cachedRtkLabel = null;
|
||||
}
|
||||
|
|
@ -656,7 +656,7 @@ export function updateProgressWidget(
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"dashboard",
|
||||
`DB status update failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`DB status update failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}, 15_000);
|
||||
|
|
|
|||
|
|
@ -31,6 +31,7 @@ import { resolveUokFlags } from "./uok/flags.js";
|
|||
import { applyModelPolicyFilter } from "./uok/model-policy.js";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getRequiredWorkflowToolsForAutoUnit } from "./workflow-tools.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
/**
|
||||
* Thrown when the model-policy gate rejects every candidate model for a unit
|
||||
* dispatch (#4959 / #4681 / #4850). The auto-loop catches this specifically
|
||||
|
|
@ -941,7 +942,7 @@ export function buildFlatRateContext(provider, ctx, prefs) {
|
|||
// fall through with authMode undefined and surface the cause.
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`flat-rate auth-mode lookup failed for ${provider}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`flat-rate auth-mode lookup failed for ${provider}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,6 +168,7 @@ import { getAutoSession } from "./auto/session.js";
|
|||
import { describeNextUnit } from "./auto-dashboard.js";
|
||||
import { _resetHasChangesCache } from "./native-git-bridge.js";
|
||||
import { autoCommitCurrentBranch } from "./worktree.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Detect summary files written directly to disk without the LLM calling
|
||||
|
|
@ -312,7 +313,7 @@ export async function autoCommitUnit(basePath, unitType, unitId, ctx) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"engine",
|
||||
`GitHub issue lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`GitHub issue lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
taskContext = {
|
||||
|
|
@ -465,7 +466,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|||
// GitHub sync not available — skip
|
||||
logWarning(
|
||||
"engine",
|
||||
`GitHub issue lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`GitHub issue lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
taskContext = {
|
||||
|
|
@ -810,7 +811,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"engine",
|
||||
`slice-cadence: failed to record milestone start SHA: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`slice-cadence: failed to record milestone start SHA: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -845,7 +846,7 @@ export async function postUnitPreVerification(pctx, opts) {
|
|||
return;
|
||||
}
|
||||
logError("engine", `slice-cadence merge failed for ${sid}`, {
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
// Non-conflict failures (dirty main, rev-walk error, etc.) can
|
||||
// leave the checkout in an unexpected state. Stop autonomous mode so
|
||||
|
|
|
|||
|
|
@ -88,6 +88,7 @@ import {
|
|||
buildResumeSection,
|
||||
} from "./workflow-helpers.js";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
// ─── Preamble Cap ─────────────────────────────────────────────────────────────
|
||||
/**
|
||||
|
|
@ -160,7 +161,7 @@ function buildCompleteSliceControlBlock(mid, sid, base) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`complete-slice task ledger failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`complete-slice task ledger failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return "";
|
||||
}
|
||||
|
|
@ -361,7 +362,7 @@ async function inlineDependencySummaries(mid, sid, base, budgetChars) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`inlineDependencySummaries DB lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`inlineDependencySummaries DB lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// If DB didn't provide depends, fall back to roadmap parsing
|
||||
|
|
@ -449,7 +450,7 @@ export async function inlineDecisionsFromDb(base, milestoneId, scope, level) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`inlineDecisionsFromDb failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`inlineDecisionsFromDb failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// DB unavailable — fall back to filesystem
|
||||
|
|
@ -485,7 +486,7 @@ export async function inlineRequirementsFromDb(
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`inlineRequirementsFromDb failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`inlineRequirementsFromDb failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return inlineSfRootFile(base, "requirements.md", "Requirements");
|
||||
|
|
@ -507,7 +508,7 @@ export async function inlineProjectFromDb(base) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`inlineProjectFromDb failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`inlineProjectFromDb failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return inlineSfRootFile(base, "project.md", "Project");
|
||||
|
|
@ -936,7 +937,7 @@ export function buildSkillActivationBlock(params) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`parseTaskPlanFile failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`parseTaskPlanFile failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2132,7 +2133,7 @@ export async function buildCompleteMilestonePrompt(mid, midTitle, base, level) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`buildCompleteMilestonePrompt DB lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`buildCompleteMilestonePrompt DB lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// File-based fallback: parse roadmap for slice IDs when DB has no data
|
||||
|
|
@ -2278,7 +2279,7 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`buildValidateMilestonePrompt verification classes lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`buildValidateMilestonePrompt verification classes lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Inline all slice summaries and assessment results
|
||||
|
|
@ -2293,7 +2294,7 @@ export async function buildValidateMilestonePrompt(mid, midTitle, base, level) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`buildValidateMilestonePrompt slice IDs lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`buildValidateMilestonePrompt slice IDs lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// File-based fallback: parse roadmap for slice IDs when DB has no data
|
||||
|
|
@ -2511,7 +2512,7 @@ export async function buildReplanSlicePrompt(mid, midTitle, sid, sTitle, base) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`loadReplanCaptures failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`loadReplanCaptures failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return loadPrompt("replan-slice", {
|
||||
|
|
@ -2684,7 +2685,7 @@ export async function buildReassessRoadmapPrompt(
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`loadDeferredCaptures failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`loadDeferredCaptures failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
const reassessCommitInstruction =
|
||||
|
|
@ -3016,7 +3017,7 @@ export async function buildRewriteDocsPrompt(
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`buildRewriteDocsPrompt DB task lookup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`buildRewriteDocsPrompt DB task lookup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
if (!incompleteTasks) {
|
||||
|
|
|
|||
|
|
@ -163,7 +163,7 @@ function getChangedFilesSinceBranch(basePath, targetBranch) {
|
|||
// merge-base failed — fall back
|
||||
logWarning(
|
||||
"recovery",
|
||||
`merge-base detection failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`merge-base detection failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Fallback: check last 20 commits
|
||||
|
|
@ -259,7 +259,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|||
// DB unavailable — treat as verified to avoid blocking
|
||||
logWarning(
|
||||
"recovery",
|
||||
`gate-evaluate DB check failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`gate-evaluate DB check failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
|
@ -306,7 +306,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"recovery",
|
||||
`parallel-research verification failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`parallel-research verification failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -329,7 +329,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"recovery",
|
||||
`plan-milestone roadmap verification failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`plan-milestone roadmap verification failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -410,7 +410,7 @@ export function verifyExpectedArtifact(unitType, unitId, base) {
|
|||
// Parse failure — don't block; slice plan may have non-standard format
|
||||
logWarning(
|
||||
"recovery",
|
||||
`plan-slice task plan verification failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`plan-slice task plan verification failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -555,7 +555,7 @@ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
|
|||
/* best-effort */
|
||||
logWarning(
|
||||
"recovery",
|
||||
`git merge-abort failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git merge-abort failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
} else if (squashMsgPath) {
|
||||
|
|
@ -565,7 +565,7 @@ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
|
|||
/* best-effort */
|
||||
logWarning(
|
||||
"recovery",
|
||||
`file unlink failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`file unlink failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -575,7 +575,7 @@ function abortAndResetMerge(basePath, hasMergeHead, squashMsgPath) {
|
|||
/* best-effort */
|
||||
logError(
|
||||
"recovery",
|
||||
`git reset failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git reset failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -112,6 +112,7 @@ import {
|
|||
isInsideWorktreesDir,
|
||||
} from "./worktree-manager.js";
|
||||
import { emitWorktreeOrphaned } from "./worktree-telemetry.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Bootstrap a fresh autonomous mode session. Handles everything from git init
|
||||
|
|
@ -143,7 +144,7 @@ export async function openProjectDbIfPresent(basePath) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"engine",
|
||||
`sf-db: failed to open existing database: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`sf-db: failed to open existing database: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -242,7 +243,7 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"engine",
|
||||
`worktree-orphaned telemetry failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`worktree-orphaned telemetry failed for ${milestoneId}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
continue;
|
||||
|
|
@ -261,7 +262,7 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
|
|||
);
|
||||
} catch (err) {
|
||||
warnings.push(
|
||||
`Failed to delete merged branch ${branch}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Failed to delete merged branch ${branch}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Clean up orphaned worktree directory if it exists
|
||||
|
|
@ -318,7 +319,7 @@ export function auditOrphanedMilestoneBranches(basePath, isolationMode) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"engine",
|
||||
`worktree-orphaned telemetry failed for ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`worktree-orphaned telemetry failed for ${milestoneId}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -470,7 +471,7 @@ export async function bootstrapAutoSession(
|
|||
/* nothing to commit */
|
||||
logWarning(
|
||||
"engine",
|
||||
`mkdir failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`mkdir failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -524,7 +525,7 @@ export async function bootstrapAutoSession(
|
|||
// Non-fatal — defensive cleanup, never block bootstrap
|
||||
logWarning(
|
||||
"bootstrap",
|
||||
`stale slice runtime reconciliation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`stale slice runtime reconciliation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Open the project-root DB before deriveState so DB-backed state
|
||||
|
|
@ -543,7 +544,7 @@ export async function bootstrapAutoSession(
|
|||
// Non-fatal — defensive cleanup, never block bootstrap
|
||||
logWarning(
|
||||
"bootstrap",
|
||||
`durable complete runtime reconciliation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`durable complete runtime reconciliation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// ── Orphaned milestone branch audit ──
|
||||
|
|
@ -571,7 +572,7 @@ export async function bootstrapAutoSession(
|
|||
// Non-fatal — the audit is defensive, never block bootstrap
|
||||
logWarning(
|
||||
"bootstrap",
|
||||
`orphaned milestone branch audit failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`orphaned milestone branch audit failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
let state = await deriveState(base);
|
||||
|
|
@ -953,7 +954,7 @@ export async function bootstrapAutoSession(
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"bootstrap",
|
||||
`Could not auto-checkout from stale milestone branch: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Could not auto-checkout from stale milestone branch: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1190,7 +1191,7 @@ export async function bootstrapAutoSession(
|
|||
}
|
||||
} catch (err) {
|
||||
ctx.ui.notify(
|
||||
`Secrets collection error: ${err instanceof Error ? err.message : String(err)}. Continuing with next task.`,
|
||||
`Secrets collection error: ${getErrorMessage(err)}. Continuing with next task.`,
|
||||
"warning",
|
||||
);
|
||||
}
|
||||
|
|
@ -1252,7 +1253,7 @@ export async function bootstrapAutoSession(
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"engine",
|
||||
`preflight validation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`preflight validation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import {
|
|||
writeUnitRuntimeRecord,
|
||||
} from "./uok/unit-runtime.js";
|
||||
import { logError, logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
/**
|
||||
* Set up all four supervision timers for the current unit:
|
||||
* 1. Soft timeout warning (wrapup)
|
||||
|
|
@ -104,7 +105,7 @@ export function startUnitSupervision(sctx) {
|
|||
// Non-fatal — fall through with no estimate
|
||||
logWarning(
|
||||
"timer",
|
||||
`operation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`operation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -424,7 +425,7 @@ export function startUnitSupervision(sctx) {
|
|||
);
|
||||
await pauseAuto(ctx, pi);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
logError("timer", `[idle-watchdog] Unhandled error: ${message}`);
|
||||
// Unblock any pending unit promise so the auto-loop is not orphaned.
|
||||
resolveAgentEndCancelled({
|
||||
|
|
@ -438,7 +439,7 @@ export function startUnitSupervision(sctx) {
|
|||
/* best effort */
|
||||
logWarning(
|
||||
"timer",
|
||||
`notification failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`notification failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -485,7 +486,7 @@ export function startUnitSupervision(sctx) {
|
|||
);
|
||||
await pauseAuto(ctx, pi);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
logError("timer", `[hard-timeout] Unhandled error: ${message}`);
|
||||
// Unblock any pending unit promise so the auto-loop is not orphaned.
|
||||
resolveAgentEndCancelled({
|
||||
|
|
@ -499,7 +500,7 @@ export function startUnitSupervision(sctx) {
|
|||
/* best effort */
|
||||
logWarning(
|
||||
"timer",
|
||||
`notification failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`notification failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,6 +68,7 @@ import {
|
|||
resolveGitDir,
|
||||
worktreePath,
|
||||
} from "./worktree-manager.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const PROJECT_PREFERENCES_FILE = "preferences.yaml";
|
||||
// ─── Shared Constants & Helpers ─────────────────────────────────────────────
|
||||
|
|
@ -152,7 +153,7 @@ function forceOverwriteAssessmentsWithVerdict(
|
|||
/* non-fatal per file */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`assessment force-copy failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`assessment force-copy failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -160,7 +161,7 @@ function forceOverwriteAssessmentsWithVerdict(
|
|||
/* non-fatal per slice */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`assessment slice scan failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`assessment slice scan failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -168,7 +169,7 @@ function forceOverwriteAssessmentsWithVerdict(
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`assessment sync failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`assessment sync failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -190,7 +191,7 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|||
if (err.code !== "ENOENT") {
|
||||
logWarning(
|
||||
"worktree",
|
||||
`file unlink failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`file unlink failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -228,7 +229,7 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|||
if (code !== "ENOENT" && code !== "EISDIR") {
|
||||
logWarning(
|
||||
"worktree",
|
||||
`untracked file unlink failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`untracked file unlink failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -239,7 +240,7 @@ function clearProjectRootStateFiles(basePath, milestoneId) {
|
|||
/* non-fatal — git command may fail if not in repo */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`untracked file cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`untracked file cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -346,7 +347,7 @@ export function syncProjectRootToWorktree(
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`worktree DB cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`worktree DB cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -496,7 +497,7 @@ export function cleanStaleRuntimeUnits(sfRootPath, hasMilestoneSummary) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`stale runtime unit unlink failed (${file}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`stale runtime unit unlink failed (${file}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -505,7 +506,7 @@ export function cleanStaleRuntimeUnits(sfRootPath, hasMilestoneSummary) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`stale runtime unit cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`stale runtime unit cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return cleaned;
|
||||
|
|
@ -544,7 +545,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`file copy failed (${f}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`file copy failed (${f}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -565,7 +566,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`preferences copy failed (${PROJECT_PREFERENCES_FILE}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`preferences copy failed (${PROJECT_PREFERENCES_FILE}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -594,7 +595,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone copy failed (${mid}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone copy failed (${mid}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -618,7 +619,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone file copy failed (${mid}/${f}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone file copy failed (${mid}/${f}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -634,7 +635,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`slices copy failed (${mid}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`slices copy failed (${mid}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
} else if (existsSync(srcSlicesDir) && existsSync(dstSlicesDir)) {
|
||||
|
|
@ -655,7 +656,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`slice copy failed (${mid}/${sid}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`slice copy failed (${mid}/${sid}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -665,7 +666,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone file sync failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone file sync failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -674,7 +675,7 @@ export function syncSfStateToWorktree(mainBasePath, worktreePath_) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone directory sync failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone directory sync failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -722,7 +723,7 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|||
// Non-fatal — file sync below is the fallback
|
||||
logError(
|
||||
"worktree",
|
||||
`DB reconciliation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`DB reconciliation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -743,7 +744,7 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`state file copy-back failed (${f}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`state file copy-back failed (${f}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -768,7 +769,7 @@ export function syncWorktreeStateBack(mainBasePath, worktreePath, milestoneId) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone sync-back failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone sync-back failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return { synced };
|
||||
|
|
@ -791,7 +792,7 @@ function syncDirFiles(srcDir, dstDir, filter, synced, prefix) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`file copy failed (${prefix}${entry.name}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`file copy failed (${prefix}${entry.name}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -799,7 +800,7 @@ function syncDirFiles(srcDir, dstDir, filter, synced, prefix) {
|
|||
/* non-fatal — srcDir may not be readable */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`directory read failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`directory read failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -854,7 +855,7 @@ function syncMilestoneDir(wtSf, mainSf, mid, synced) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone slice sync failed (${mid}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone slice sync failed (${mid}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -893,7 +894,7 @@ export function runWorktreePostCreateHook(sourceDir, worktreeDir, hookPath) {
|
|||
/* keep original */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`realpath failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`realpath failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -915,7 +916,7 @@ export function runWorktreePostCreateHook(sourceDir, worktreeDir, hookPath) {
|
|||
shell: needsShell,
|
||||
});
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
errors.push(`Worktree post-create hook failed: ${msg}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -939,7 +940,7 @@ export function runWorktreePostCreateHook(sourceDir, worktreeDir, hookPath) {
|
|||
timeout: 60_000,
|
||||
});
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
errors.push(`workspace.after_create hook failed: ${msg}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -999,7 +1000,7 @@ function reconcilePlanCheckboxes(projectRoot, wtPath, milestoneId) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`walkMd directory read failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`walkMd directory read failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return results;
|
||||
|
|
@ -1051,7 +1052,7 @@ function reconcilePlanCheckboxes(projectRoot, wtPath, milestoneId) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`plan checkbox reconcile write failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`plan checkbox reconcile write failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1148,7 +1149,7 @@ export function createAutoWorktree(basePath, milestoneId) {
|
|||
// Don't store originalBase -- caller can retry or clean up.
|
||||
throw new SFError(
|
||||
SF_IO_ERROR,
|
||||
`Auto-worktree created at ${info.path} but chdir failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Auto-worktree created at ${info.path} but chdir failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
nudgeGitBranchCache(previousCwd);
|
||||
|
|
@ -1212,7 +1213,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|||
} catch (err) {
|
||||
throw new SFError(
|
||||
SF_IO_ERROR,
|
||||
`Failed to chdir back to ${originalBasePath} during teardown: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Failed to chdir back to ${originalBasePath} during teardown: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
nudgeGitBranchCache(previousCwd);
|
||||
|
|
@ -1241,7 +1242,7 @@ export function teardownAutoWorktree(originalBasePath, milestoneId, opts = {}) {
|
|||
// Non-fatal — the warning above tells the user how to clean up
|
||||
logWarning(
|
||||
"worktree",
|
||||
`worktree directory removal failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`worktree directory removal failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -1335,7 +1336,7 @@ export function enterAutoWorktree(basePath, milestoneId) {
|
|||
} catch (err) {
|
||||
throw new SFError(
|
||||
SF_IO_ERROR,
|
||||
`Failed to enter auto-worktree at ${p}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Failed to enter auto-worktree at ${p}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
nudgeGitBranchCache(previousCwd);
|
||||
|
|
@ -1460,7 +1461,7 @@ export function mergeMilestoneToMain(
|
|||
/* non-fatal */
|
||||
logError(
|
||||
"worktree",
|
||||
`DB reconciliation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`DB reconciliation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1632,7 +1633,7 @@ export function mergeMilestoneToMain(
|
|||
// report the dirty tree if it fails.
|
||||
logWarning(
|
||||
"worktree",
|
||||
`git stash failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git stash failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// 7a. Shelter queued milestone directories before the squash merge (#2505).
|
||||
|
|
@ -1659,7 +1660,7 @@ export function mergeMilestoneToMain(
|
|||
/* best-effort */
|
||||
logError(
|
||||
"worktree",
|
||||
`shelter restore failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`shelter restore failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1669,7 +1670,7 @@ export function mergeMilestoneToMain(
|
|||
/* best-effort */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`shelter cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`shelter cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
};
|
||||
|
|
@ -1691,7 +1692,7 @@ export function mergeMilestoneToMain(
|
|||
// Non-fatal — if shelter fails, the merge may still succeed
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone shelter failed (${entry.name}): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone shelter failed (${entry.name}): ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1700,7 +1701,7 @@ export function mergeMilestoneToMain(
|
|||
// Non-fatal — proceed with merge; untracked files may block it
|
||||
logWarning(
|
||||
"worktree",
|
||||
`milestone shelter operation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone shelter operation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// 7b. Clean up stale merge state before attempting squash merge (#2912).
|
||||
|
|
@ -1718,7 +1719,7 @@ export function mergeMilestoneToMain(
|
|||
/* best-effort */
|
||||
logError(
|
||||
"worktree",
|
||||
`merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`merge state cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// 8. Squash merge — auto-resolve .sf/ state file conflicts (#530)
|
||||
|
|
@ -1740,7 +1741,7 @@ export function mergeMilestoneToMain(
|
|||
/* best-effort */
|
||||
logError(
|
||||
"worktree",
|
||||
`merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`merge state cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Pop stash before throwing so local work is not lost.
|
||||
|
|
@ -1755,7 +1756,7 @@ export function mergeMilestoneToMain(
|
|||
/* stash pop conflict is non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`git stash pop failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git stash pop failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1815,7 +1816,7 @@ export function mergeMilestoneToMain(
|
|||
/* best-effort */
|
||||
logError(
|
||||
"worktree",
|
||||
`git merge-abort failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git merge-abort failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
try {
|
||||
|
|
@ -1828,7 +1829,7 @@ export function mergeMilestoneToMain(
|
|||
/* best-effort */
|
||||
logError(
|
||||
"worktree",
|
||||
`merge state file cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`merge state file cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Pop stash before throwing so local work is not lost (#2151).
|
||||
|
|
@ -1843,7 +1844,7 @@ export function mergeMilestoneToMain(
|
|||
/* stash pop conflict is non-fatal */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`git stash pop failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git stash pop failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1883,7 +1884,7 @@ export function mergeMilestoneToMain(
|
|||
/* best-effort */
|
||||
logError(
|
||||
"worktree",
|
||||
`post-commit merge state cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`post-commit merge state cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// 9a-ii. Restore stashed files now that the merge+commit is complete (#2151).
|
||||
|
|
@ -1942,7 +1943,7 @@ export function mergeMilestoneToMain(
|
|||
/* stash may already be consumed */
|
||||
logWarning(
|
||||
"worktree",
|
||||
`git stash drop failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git stash drop failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -2022,7 +2023,7 @@ export function mergeMilestoneToMain(
|
|||
// Push failure is non-fatal
|
||||
logWarning(
|
||||
"worktree",
|
||||
`git push failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git push failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2065,7 +2066,7 @@ export function mergeMilestoneToMain(
|
|||
// PR creation failure is non-fatal — gh may not be installed or authenticated
|
||||
logWarning(
|
||||
"worktree",
|
||||
`PR creation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`PR creation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -2125,7 +2126,7 @@ export function mergeMilestoneToMain(
|
|||
// Best-effort -- worktree dir may already be gone
|
||||
logWarning(
|
||||
"worktree",
|
||||
`worktree removal failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`worktree removal failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// 13. Delete milestone branch (after worktree removal so ref is unlocked)
|
||||
|
|
@ -2135,7 +2136,7 @@ export function mergeMilestoneToMain(
|
|||
// Best-effort
|
||||
logWarning(
|
||||
"worktree",
|
||||
`git branch-delete failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`git branch-delete failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// 14. Clear module state
|
||||
|
|
|
|||
|
|
@ -418,7 +418,7 @@ export function getAutoDashboardData() {
|
|||
// Non-fatal — captures module may not be loaded
|
||||
logWarning(
|
||||
"engine",
|
||||
`capture count failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`capture count failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -748,7 +748,7 @@ function cleanupAfterLoopExit(ctx) {
|
|||
/* best-effort — mirror stopAuto cleanup */
|
||||
logWarning(
|
||||
"session",
|
||||
`lock cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`lock cleanup failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -769,7 +769,7 @@ function cleanupAfterLoopExit(ctx) {
|
|||
/* best-effort */
|
||||
logWarning(
|
||||
"engine",
|
||||
`chdir failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`chdir failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -869,7 +869,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|||
// Non-fatal — fall through to preserveBranch path
|
||||
logWarning(
|
||||
"engine",
|
||||
`milestone summary check failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`milestone summary check failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -923,7 +923,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|||
/* best-effort */
|
||||
logWarning(
|
||||
"engine",
|
||||
`chdir failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`chdir failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -1051,7 +1051,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"engine",
|
||||
`file unlink failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`file unlink failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -1094,7 +1094,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|||
/* non-fatal: browser-tools may not be loaded */
|
||||
logWarning(
|
||||
"engine",
|
||||
`browser teardown failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`browser teardown failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -1151,7 +1151,7 @@ export async function stopAuto(ctx, pi, reason) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"engine",
|
||||
`auto-exit telemetry failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`auto-exit telemetry failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Drop the active-tool baseline so a subsequent /autonomous run on the
|
||||
|
|
@ -1222,7 +1222,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|||
// Non-fatal — resume will still work via full bootstrap, just without worktree context
|
||||
logWarning(
|
||||
"engine",
|
||||
`paused-session file write failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`paused-session file write failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -1240,7 +1240,7 @@ export async function pauseAuto(ctx, _pi, _errorContext) {
|
|||
// Non-fatal — best-effort closeout on pause
|
||||
logWarning(
|
||||
"engine",
|
||||
`unit closeout on pause failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`unit closeout on pause failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -1593,7 +1593,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|||
if (err.code !== "ENOENT") {
|
||||
logWarning(
|
||||
"session",
|
||||
`pause file cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`pause file cleanup failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -1665,7 +1665,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|||
// Malformed or missing — proceed with fresh bootstrap
|
||||
logWarning(
|
||||
"session",
|
||||
`paused-session restore failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`paused-session restore failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -1877,7 +1877,7 @@ export async function startAuto(ctx, pi, base, verboseMode, options) {
|
|||
// Best-effort only — sidebar sync must never block autonomous mode startup
|
||||
logWarning(
|
||||
"engine",
|
||||
`cmux sync failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`cmux sync failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -2038,7 +2038,7 @@ export async function dispatchHookUnit(
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`hook model set failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`hook model set failed: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
@ -2075,7 +2075,7 @@ export async function dispatchHookUnit(
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"engine",
|
||||
`chdir failed before hook dispatch: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`chdir failed before hook dispatch: ${getErrorMessage(err)}`,
|
||||
{ file: "auto.ts" },
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@
|
|||
* retrying. Each retry re-dispatches the unit at full LLM cost, so we bail
|
||||
* immediately rather than burning budget on guaranteed failures.
|
||||
*/
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
export const INFRA_ERROR_CODES = new Set([
|
||||
"ENOSPC", // disk full
|
||||
"ENOMEM", // out of memory
|
||||
|
|
@ -35,7 +36,7 @@ export function isInfrastructureError(err) {
|
|||
const code = err.code;
|
||||
if (typeof code === "string" && INFRA_ERROR_CODES.has(code)) return code;
|
||||
}
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
for (const code of INFRA_ERROR_CODES) {
|
||||
if (msg.includes(code)) return code;
|
||||
}
|
||||
|
|
@ -65,7 +66,7 @@ export function isTransientCooldownError(err) {
|
|||
return true;
|
||||
}
|
||||
// Fallback: message match for cross-process error propagation
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
return /in a cooldown window/i.test(msg);
|
||||
}
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ import {
|
|||
} from "./phases.js";
|
||||
import { _clearCurrentResolve } from "./resolve.js";
|
||||
import { MAX_LOOP_ITERATIONS } from "./types.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
// ── Stuck detection persistence (#3704) ──────────────────────────────────
|
||||
// Persist stuck detection state to disk so it survives session restarts.
|
||||
|
|
@ -81,7 +82,7 @@ function loadStuckState(basePath) {
|
|||
} catch (err) {
|
||||
debugLog("autoLoop", {
|
||||
phase: "load-stuck-state-failed",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
return { recentUnits: [], stuckRecoveryAttempts: 0 };
|
||||
}
|
||||
|
|
@ -102,7 +103,7 @@ function saveStuckState(basePath, state) {
|
|||
} catch (err) {
|
||||
debugLog("autoLoop", {
|
||||
phase: "save-stuck-state-failed",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -142,7 +143,7 @@ function hydrateCustomVerifyRetryCounts(s) {
|
|||
} catch (err) {
|
||||
debugLog("autoLoop", {
|
||||
phase: "load-custom-verify-retries-failed",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
return s.verificationRetryCount;
|
||||
|
|
@ -169,7 +170,7 @@ function saveCustomVerifyRetryCounts(s) {
|
|||
if (code !== "ENOENT") {
|
||||
debugLog("autoLoop", {
|
||||
phase: "save-custom-verify-retries-failed",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -417,7 +418,7 @@ async function runExitSolverEval(ctx, s, deps, iteration) {
|
|||
error: result.error,
|
||||
});
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
ctx.ui.notify(`Autonomous solver eval hook failed: ${message}`, "warning", {
|
||||
noticeKind: NOTICE_KIND.TOOL_NOTICE,
|
||||
dedupe_key: `solver-eval-hook-fail:${message.slice(0, 120)}`,
|
||||
|
|
@ -587,7 +588,7 @@ export async function autoLoop(ctx, pi, s, deps) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`sidecar queue scheduling failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`sidecar queue scheduling failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -121,6 +121,7 @@ import {
|
|||
withTimeout,
|
||||
} from "./finalize-timeout.js";
|
||||
import { runUnit } from "./run-unit.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
import {
|
||||
BUDGET_THRESHOLDS,
|
||||
MAX_FINALIZE_TIMEOUTS,
|
||||
|
|
@ -657,7 +658,7 @@ export async function runPreDispatch(ic, loopState) {
|
|||
} catch (err) {
|
||||
debugLog("autoLoop", {
|
||||
phase: "slice-parallel-check-error",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
// Non-fatal — fall through to sequential dispatch
|
||||
}
|
||||
|
|
@ -696,7 +697,7 @@ export async function runPreDispatch(ic, loopState) {
|
|||
await generateMilestoneReport(s, ctx, s.currentMilestoneId);
|
||||
} catch (err) {
|
||||
ctx.ui.notify(
|
||||
`Report generation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Report generation failed: ${getErrorMessage(err)}`,
|
||||
"warning",
|
||||
);
|
||||
}
|
||||
|
|
@ -1132,7 +1133,7 @@ export async function runDispatch(ic, preData, loopState) {
|
|||
}
|
||||
} catch (err) {
|
||||
logWarning("engine", "UOK diagnostics dispatch gate failed open", {
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
deps.emitJournalEvent({
|
||||
|
|
@ -1172,7 +1173,7 @@ export async function runDispatch(ic, preData, loopState) {
|
|||
}
|
||||
} catch (err) {
|
||||
logWarning("engine", "Reasoning assist failed open", {
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
unitType,
|
||||
unitId,
|
||||
});
|
||||
|
|
@ -1720,7 +1721,7 @@ export async function runGuards(ic, mid, unitType, unitId, sliceId) {
|
|||
}
|
||||
} catch (err) {
|
||||
ctx.ui.notify(
|
||||
`Secrets collection error: ${err instanceof Error ? err.message : String(err)}. Continuing with next task.`,
|
||||
`Secrets collection error: ${getErrorMessage(err)}. Continuing with next task.`,
|
||||
"warning",
|
||||
);
|
||||
}
|
||||
|
|
@ -2662,7 +2663,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|||
? () => {
|
||||
void resumeAutoAfterProviderDelay(pi, ctx).catch((err) => {
|
||||
const message =
|
||||
err instanceof Error ? err.message : String(err);
|
||||
getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Session timeout recovery failed: ${message}`,
|
||||
"error",
|
||||
|
|
@ -2856,7 +2857,7 @@ export async function runUnitPhase(ic, iterData, loopState, sidecarItem) {
|
|||
/* non-fatal — anchor is advisory */
|
||||
logWarning(
|
||||
"engine",
|
||||
`phase anchor failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`phase anchor failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ import { dirname, isAbsolute, join, relative, resolve } from "node:path";
|
|||
import { atomicWriteSync } from "./atomic-write.js";
|
||||
import { ensureDbOpen } from "./bootstrap/dynamic-tools.js";
|
||||
import { sfRoot } from "./paths.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const DEFAULT_TIMEOUT_MS = 5 * 60_000;
|
||||
const MAX_OUTPUT_CHARS = 20_000;
|
||||
|
|
@ -46,7 +47,7 @@ function parseJsonLine(line, index, filePath) {
|
|||
return JSON.parse(line);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`${filePath}:${index + 1}: invalid JSON: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`${filePath}:${index + 1}: invalid JSON: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -480,7 +481,7 @@ export async function runAutomaticAutonomousSolverEval(options) {
|
|||
});
|
||||
return { ok: true, report };
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
emitJournalEvent({
|
||||
ts: new Date().toISOString(),
|
||||
eventType: "solver-eval-auto-failed",
|
||||
|
|
@ -581,7 +582,7 @@ async function recordEvalRunBestEffort(basePath, report) {
|
|||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -662,7 +663,7 @@ export async function handleAutonomousSolverEval(
|
|||
args = parseAutonomousSolverEvalArgs(rawArgs);
|
||||
} catch (err) {
|
||||
ctx.ui.notify(
|
||||
`Usage: /solver-eval [run|history|show <run-id>] [--sample | --cases <jsonl>] [--run-id <id>] [--limit <n>]\n${err instanceof Error ? err.message : String(err)}`,
|
||||
`Usage: /solver-eval [run|history|show <run-id>] [--sample | --cases <jsonl>] [--run-id <id>] [--limit <n>]\n${getErrorMessage(err)}`,
|
||||
"warning",
|
||||
);
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
import { pauseAutoForProviderError } from "../provider-error-pause.js";
|
||||
import { logWarning } from "../workflow-logger.js";
|
||||
import { clearDiscussionFlowState } from "./write-gate.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const retryState = createRetryState();
|
||||
const GEMINI_CAPACITY_COOLDOWN_MS = 2 * 60_000;
|
||||
|
|
@ -145,7 +146,7 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|||
resetRetryState(retryState);
|
||||
resolveAgentEnd(event);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Autonomous mode error after empty-content abort: ${message}. Stopping autonomous mode.`,
|
||||
"error",
|
||||
|
|
@ -228,7 +229,7 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|||
"warning",
|
||||
);
|
||||
} catch (err) {
|
||||
const m = err instanceof Error ? err.message : String(err);
|
||||
const m = getErrorMessage(err);
|
||||
logWarning("bootstrap", `Failed to persist blocked model: ${m}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -280,7 +281,7 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|||
"warning",
|
||||
);
|
||||
} catch (err) {
|
||||
const m = err instanceof Error ? err.message : String(err);
|
||||
const m = getErrorMessage(err);
|
||||
logWarning("bootstrap", `Failed to persist model cooldown: ${m}`);
|
||||
}
|
||||
}
|
||||
|
|
@ -343,7 +344,7 @@ export async function handleAgentEnd(pi, event, ctx) {
|
|||
resetRetryState(retryState);
|
||||
resolveAgentEnd(event);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Autonomous mode error in agent_end handler: ${message}. Stopping autonomous mode.`,
|
||||
"error",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
} from "../tools/workflow-tool-executors.js";
|
||||
import { logError } from "../workflow-logger.js";
|
||||
import { ensureDbOpen } from "./dynamic-tools.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
export function registerDbTools(pi) {
|
||||
// ─── save_decision ─────────────────────────────────────────────────
|
||||
const decisionSaveExecute = async (
|
||||
|
|
@ -68,7 +69,7 @@ export function registerDbTools(pi) {
|
|||
details: { operation: "save_decision", id },
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `save_decision tool failed: ${msg}`, {
|
||||
tool: "save_decision",
|
||||
error: String(err),
|
||||
|
|
@ -190,7 +191,7 @@ export function registerDbTools(pi) {
|
|||
details: { operation: "update_requirement", id: params.id },
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `update_requirement tool failed: ${msg}`, {
|
||||
tool: "update_requirement",
|
||||
error: String(err),
|
||||
|
|
@ -307,7 +308,7 @@ export function registerDbTools(pi) {
|
|||
details: { operation: "save_requirement", id: result.id },
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `save_requirement tool failed: ${msg}`, {
|
||||
tool: "save_requirement",
|
||||
error: String(err),
|
||||
|
|
@ -484,7 +485,7 @@ export function registerDbTools(pi) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
return {
|
||||
content: [
|
||||
{
|
||||
|
|
@ -613,7 +614,7 @@ export function registerDbTools(pi) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `report_issue tool failed: ${msg}`, {
|
||||
tool: "report_issue",
|
||||
error: String(err),
|
||||
|
|
@ -769,7 +770,7 @@ export function registerDbTools(pi) {
|
|||
details: { operation: "save_knowledge", id },
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `save_knowledge tool failed: ${msg}`, {
|
||||
tool: "save_knowledge",
|
||||
error: String(err),
|
||||
|
|
@ -900,7 +901,7 @@ export function registerDbTools(pi) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `resolve_issue tool failed: ${msg}`, {
|
||||
tool: "resolve_issue",
|
||||
error: String(err),
|
||||
|
|
@ -1010,7 +1011,7 @@ export function registerDbTools(pi) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `checkpoint tool failed: ${msg}`, {
|
||||
tool: "checkpoint",
|
||||
error: String(err),
|
||||
|
|
@ -1745,7 +1746,7 @@ export function registerDbTools(pi) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `plan_task tool failed: ${msg}`, {
|
||||
tool: "plan_task",
|
||||
error: String(err),
|
||||
|
|
@ -2183,7 +2184,7 @@ export function registerDbTools(pi) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `skip_slice tool failed: ${msg}`, {
|
||||
tool: "skip_slice",
|
||||
error: String(err),
|
||||
|
|
@ -2758,7 +2759,7 @@ export function registerDbTools(pi) {
|
|||
details: { operation: "chapter_open", id },
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
return {
|
||||
content: [{ type: "text", text: `Error opening chapter: ${msg}` }],
|
||||
details: { operation: "chapter_open", error: msg },
|
||||
|
|
@ -2839,7 +2840,7 @@ export function registerDbTools(pi) {
|
|||
details: { operation: "chapter_close", id: params.id, closed },
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
return {
|
||||
content: [{ type: "text", text: `Error closing chapter: ${msg}` }],
|
||||
details: { operation: "chapter_close", error: msg },
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { executeExecSearch } from "../tools/exec-search-tool.js";
|
|||
import { executeSfExec } from "../tools/exec-tool.js";
|
||||
import { executeResume } from "../tools/resume-tool.js";
|
||||
import { logWarning } from "../workflow-logger.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
export function registerExecTools(pi) {
|
||||
pi.registerTool({
|
||||
name: "run_command",
|
||||
|
|
@ -68,7 +69,7 @@ export function registerExecTools(pi) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"tool",
|
||||
`run_command could not load preferences: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`run_command could not load preferences: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
onUpdate?.({
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { Type } from "@sinclair/typebox";
|
||||
import { queryJournal } from "../journal.js";
|
||||
import { logWarning } from "../workflow-logger.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
export function registerJournalTools(pi) {
|
||||
pi.registerTool({
|
||||
name: "query_journal",
|
||||
|
|
@ -77,7 +78,7 @@ export function registerJournalTools(pi) {
|
|||
details: { operation: "journal_query", count: limited.length },
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logWarning("tool", `query_journal tool failed: ${msg}`);
|
||||
return {
|
||||
content: [{ type: "text", text: `Error querying journal: ${msg}` }],
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { registerQueryTools } from "./query-tools.js";
|
|||
import { registerHooks } from "./register-hooks.js";
|
||||
import { registerShortcuts } from "./register-shortcuts.js";
|
||||
import { registerSessionTodoTool } from "./session-todo-tools.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
export { writeCrashLog } from "./crash-log.js";
|
||||
export function handleRecoverableExtensionProcessError(err) {
|
||||
|
|
@ -101,7 +102,7 @@ export function registerSfExtension(pi) {
|
|||
void loadEcosystemExtensions(pi, ecosystemHandlers).catch((err) => {
|
||||
logWarning(
|
||||
"bootstrap",
|
||||
`Failed to load ecosystem extensions: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Failed to load ecosystem extensions: ${getErrorMessage(err)}`,
|
||||
);
|
||||
});
|
||||
},
|
||||
|
|
@ -113,7 +114,7 @@ export function registerSfExtension(pi) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"bootstrap",
|
||||
`Failed to register ${name}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Failed to register ${name}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ import {
|
|||
shouldBlockPendingGateBash,
|
||||
shouldBlockQueueExecution,
|
||||
} from "./write-gate.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
// Skip the welcome screen on the very first session_start — cli.ts already
|
||||
// printed it before the TUI launched. Only re-print on /clear (subsequent sessions).
|
||||
|
|
@ -293,7 +294,7 @@ export function registerHooks(pi, ecosystemHandlers = []) {
|
|||
const { logWarning } = await import("../workflow-logger.js");
|
||||
logWarning(
|
||||
"session-start",
|
||||
`Failed to initialize metrics-central: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Failed to initialize metrics-central: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// Apply show_token_cost preference (#1515)
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
openDatabase,
|
||||
readTransaction,
|
||||
} from "./sf-db.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
function milestoneDir(basePath, milestoneId) {
|
||||
return join(basePath, ".sf", "milestones", milestoneId);
|
||||
|
|
@ -246,7 +247,7 @@ export function getCanonicalMilestonePlan(basePath, milestoneId, options = {}) {
|
|||
return blockedResult(
|
||||
"db-unavailable",
|
||||
milestoneId,
|
||||
`.sf/sf.db exists but could not be read: ${err instanceof Error ? err.message : String(err)}. Runtime does not fall back to projections when DB is expected; run sf recover.`,
|
||||
`.sf/sf.db exists but could not be read: ${getErrorMessage(err)}. Runtime does not fall back to projections when DB is expected; run sf recover.`,
|
||||
paths,
|
||||
);
|
||||
}
|
||||
|
|
@ -273,7 +274,7 @@ export function getCanonicalMilestonePlan(basePath, milestoneId, options = {}) {
|
|||
return blockedResult(
|
||||
"projection-invalid",
|
||||
milestoneId,
|
||||
err instanceof Error ? err.message : String(err),
|
||||
getErrorMessage(err),
|
||||
paths,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
* Entry point: handleChangelog() called from commands.ts
|
||||
*/
|
||||
// ─── Semver comparison ────────────────────────────────────────────────────────
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
function compareSemver(a, b) {
|
||||
const pa = a.split(".").map(Number);
|
||||
const pb = b.split(".").map(Number);
|
||||
|
|
@ -89,7 +90,7 @@ export async function handleChangelog(args, ctx, pi) {
|
|||
}
|
||||
releases = await response.json();
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to fetch changelog: ${message}`, "error");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ import { execFileSync } from "node:child_process";
|
|||
import { GIT_NO_PROMPT_ENV } from "./git-constants.js";
|
||||
import { nativeHasChanges } from "./native-git-bridge.js";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
/**
|
||||
* Check the working tree for dirty files before a milestone merge.
|
||||
*
|
||||
|
|
@ -37,7 +38,7 @@ export function preflightCleanRoot(basePath, milestoneId, notify) {
|
|||
// If the status check itself fails, treat as clean and let the merge decide
|
||||
logWarning(
|
||||
"preflight",
|
||||
`clean-root status check failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`clean-root status check failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return { stashPushed: false, summary: "" };
|
||||
}
|
||||
|
|
@ -65,7 +66,7 @@ export function preflightCleanRoot(basePath, milestoneId, notify) {
|
|||
};
|
||||
} catch (err) {
|
||||
// Stash failure is non-fatal — log and let the merge attempt proceed
|
||||
const msg = `git stash push failed before merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}`;
|
||||
const msg = `git stash push failed before merge of milestone ${milestoneId}: ${getErrorMessage(err)}`;
|
||||
logWarning("preflight", msg);
|
||||
notify(
|
||||
`Auto-stash failed before milestone ${milestoneId} merge — proceeding anyway. ${msg}`,
|
||||
|
|
@ -96,7 +97,7 @@ export function postflightPopStash(basePath, milestoneId, notify) {
|
|||
} catch (err) {
|
||||
// Pop conflicts mean the merged code collides with the stashed changes.
|
||||
// Log a warning — the user needs to resolve manually, but the merge succeeded.
|
||||
const msg = `git stash pop failed after merge of milestone ${milestoneId}: ${err instanceof Error ? err.message : String(err)}. Run "git stash pop" manually to restore your changes.`;
|
||||
const msg = `git stash pop failed after merge of milestone ${milestoneId}: ${getErrorMessage(err)}. Run "git stash pop" manually to restore your changes.`;
|
||||
logWarning("preflight", msg);
|
||||
notify(msg, "warning");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
writeFileSync,
|
||||
} from "node:fs";
|
||||
import { delimiter, isAbsolute, join, relative, resolve } from "node:path";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const SIFT_BINARY_NAME = process.platform === "win32" ? "sift.exe" : "sift";
|
||||
const DEFAULT_SIFT_WARMUP_TTL_MS = 6 * 60 * 60 * 1000;
|
||||
|
|
@ -621,7 +622,7 @@ export function ensureSiftIndexWarmup(projectRoot, prefs, options = {}) {
|
|||
} catch (err) {
|
||||
return {
|
||||
status: "error",
|
||||
reason: err instanceof Error ? err.message : String(err),
|
||||
reason: getErrorMessage(err),
|
||||
command,
|
||||
args,
|
||||
markerPath,
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { join } from "node:path";
|
|||
import { resolveSliceFile, sfRoot } from "./paths.js";
|
||||
import { loadPrompt } from "./prompt-loader.js";
|
||||
import { deriveState } from "./state.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
function findLastCompletedSlice(basePath, milestoneId) {
|
||||
// Scan disk for slices that have a SUMMARY.md (indicating completion)
|
||||
|
|
@ -126,7 +127,7 @@ export async function handleAddTests(args, ctx, pi) {
|
|||
{ triggerTurn: true },
|
||||
);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to dispatch test generation: ${msg}`, "error");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import {
|
|||
updateDebugSession,
|
||||
} from "./debug-session-store.js";
|
||||
import { loadPrompt } from "./prompt-loader.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const SUBCOMMANDS = new Set(["list", "status", "continue", "--diagnose"]);
|
||||
function isValidSlugCandidate(input) {
|
||||
|
|
@ -127,7 +128,7 @@ export async function handleDebug(args, ctx, pi) {
|
|||
{ triggerTurn: true },
|
||||
);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Debug dispatch failed: ${msg}\nSession '${s.slug}' is persisted; retry with /debug continue ${s.slug}`,
|
||||
"warning",
|
||||
|
|
@ -364,7 +365,7 @@ export async function handleDebug(args, ctx, pi) {
|
|||
{ triggerTurn: true },
|
||||
);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Continue dispatch failed: ${msg}\nSession '${resumed.session.slug}' is persisted; retry with /debug continue ${resumed.session.slug}`,
|
||||
"warning",
|
||||
|
|
@ -418,7 +419,7 @@ export async function handleDebug(args, ctx, pi) {
|
|||
{ triggerTurn: true },
|
||||
);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Diagnose dispatch failed: ${msg}\nSession '${s.slug}' is persisted; continue manually with /debug continue ${s.slug}`,
|
||||
"warning",
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@ import {
|
|||
resolveSlicePath,
|
||||
} from "./paths.js";
|
||||
import { deriveState } from "./state.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
// ─── Constants ────────────────────────────────────────────────────────────────
|
||||
/**
|
||||
* Slice-ID format. Must match the canonical `/^S\d+$/` used elsewhere in the
|
||||
|
|
@ -228,7 +229,7 @@ export async function buildEvalReviewContext(
|
|||
specTruncated = true;
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
spec = bestFitMarker(
|
||||
remaining,
|
||||
`[truncated: failed to read AI-SPEC.md (${msg})]`,
|
||||
|
|
@ -553,7 +554,7 @@ export async function handleEvalReview(args, ctx, pi) {
|
|||
"info",
|
||||
);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to read ${action.path}: ${msg}`, "error");
|
||||
}
|
||||
return;
|
||||
|
|
@ -581,7 +582,7 @@ export async function handleEvalReview(args, ctx, pi) {
|
|||
try {
|
||||
context = await buildEvalReviewContext(detected, milestoneId);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to build eval-review context: ${msg}`, "error");
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import { sfRoot } from "./paths.js";
|
|||
import { sfHome } from "./sf-home.js";
|
||||
import { loadPrompt } from "./prompt-loader.js";
|
||||
import { deriveState } from "./state.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const UPDATE_REGISTRY_URL =
|
||||
"https://registry.npmjs.org/singularity-forge/latest";
|
||||
|
|
@ -353,7 +354,7 @@ export async function handleTriage(args, ctx, pi, basePath) {
|
|||
);
|
||||
} catch (err) {
|
||||
ctx.ui.notify(
|
||||
`TODO triage failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`TODO triage failed: ${getErrorMessage(err)}`,
|
||||
"warning",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import {
|
|||
} from "./native-git-bridge.js";
|
||||
import { deriveState } from "./state.js";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
/**
|
||||
* Clean up merged and stale milestone branches.
|
||||
*/
|
||||
|
|
@ -625,7 +626,7 @@ export async function handleRecover(ctx, basePath) {
|
|||
);
|
||||
ctx.ui.notify(lines.join("\n"), "success");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logWarning("command", `recover failed: ${msg}`);
|
||||
ctx.ui.notify(`sf recover failed: ${msg}`, "error");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import {
|
|||
nativeDetectMainBranch,
|
||||
nativeGetCurrentBranch,
|
||||
} from "./native-git-bridge.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const EXCLUDED_PATHS = [".sf", ".planning", "PLAN.md"];
|
||||
function git(basePath, args) {
|
||||
|
|
@ -213,7 +214,7 @@ export async function handlePrBranch(args, ctx) {
|
|||
gitAllowFail(basePath, ["cherry-pick", "--abort"]);
|
||||
gitAllowFail(basePath, ["reset", "--hard", "HEAD"]);
|
||||
gitAllowFail(basePath, ["checkout", currentBranch]);
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to create PR branch: ${msg}`, "error");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
import { existsSync, mkdirSync } from "node:fs";
|
||||
import { join, relative } from "node:path";
|
||||
import { loadPrompt } from "./prompt-loader.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
// ─── Constants ────────────────────────────────────────────────────────────────
|
||||
export const DEFAULT_FOCUS = "tech+arch";
|
||||
export const VALID_FOCUS_AREAS = [
|
||||
|
|
@ -97,7 +98,7 @@ export async function handleScan(args, ctx, pi) {
|
|||
{ triggerTurn: true },
|
||||
);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to dispatch scan: ${msg}`, "error");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import {
|
|||
resolveSlicePath,
|
||||
} from "./paths.js";
|
||||
import { deriveState } from "./state.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
function git(basePath, args) {
|
||||
return execFileSync("git", args, { cwd: basePath, encoding: "utf-8" }).trim();
|
||||
|
|
@ -231,7 +232,7 @@ export async function handleShip(args, ctx, _pi) {
|
|||
}).trim();
|
||||
ctx.ui.notify(`PR created: ${prUrl}`, "success");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to create PR: ${msg}`, "error");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import {
|
|||
insertTriageSkill,
|
||||
openDatabase,
|
||||
} from "./sf-db.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const _EMPTY_TODO = "# TODO\n\nDump anything here.\n";
|
||||
const MAX_DUMP_CHARS = 48_000;
|
||||
|
|
@ -505,7 +506,7 @@ export function validateJsonlFile(path, schemaName) {
|
|||
} catch (err) {
|
||||
return {
|
||||
ok: false,
|
||||
error: `${schemaName} line ${i + 1}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
error: `${schemaName} line ${i + 1}: ${getErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -665,7 +666,7 @@ export async function handleTodo(args, ctx, _pi) {
|
|||
);
|
||||
} catch (err) {
|
||||
ctx.ui.notify(
|
||||
`TODO triage failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`TODO triage failed: ${getErrorMessage(err)}`,
|
||||
"warning",
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
nativeHasChanges,
|
||||
} from "./native-git-bridge.js";
|
||||
import { autoCommitCurrentBranch } from "./worktree.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
import {
|
||||
diffWorktreeAll,
|
||||
diffWorktreeNumstat,
|
||||
|
|
@ -146,7 +147,7 @@ async function handleMerge(args, ctx) {
|
|||
removeWorktree(basePath, target, { deleteBranch: true });
|
||||
ctx.ui.notify(`Removed empty worktree ${target}.`, "info");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Worktree partially removed: ${msg}\n\nRun 'git worktree prune' to clean up any dangling registrations.`,
|
||||
"error",
|
||||
|
|
@ -158,7 +159,7 @@ async function handleMerge(args, ctx) {
|
|||
try {
|
||||
autoCommitCurrentBranch(wt.path, "worktree-merge", target);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
[
|
||||
`Auto-commit before merge failed: ${msg}`,
|
||||
|
|
@ -176,7 +177,7 @@ async function handleMerge(args, ctx) {
|
|||
try {
|
||||
mergeWorktreeToMain(basePath, target, commitMessage);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
if (err instanceof SFError && err.code === SF_GIT_ERROR) {
|
||||
ctx.ui.notify(
|
||||
`Merge requires the main branch to be checked out: ${msg}\n\nSwitch to ${mainBranch} (e.g. 'git checkout ${mainBranch}'), then re-run /worktree merge ${target}.`,
|
||||
|
|
@ -199,7 +200,7 @@ async function handleMerge(args, ctx) {
|
|||
removeWorktree(basePath, target, { deleteBranch: true });
|
||||
ctx.ui.notify(successLines.join("\n"), "info");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
const cleanupLines = [
|
||||
...successLines,
|
||||
"",
|
||||
|
|
@ -228,7 +229,7 @@ async function handleClean(ctx) {
|
|||
removeWorktree(basePath, wt.name, { deleteBranch: true });
|
||||
removed.push(wt.name);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
kept.push(`${wt.name} (failed: ${msg})`);
|
||||
}
|
||||
} else {
|
||||
|
|
@ -286,7 +287,7 @@ async function handleRemove(args, ctx) {
|
|||
removeWorktree(basePath, name, { deleteBranch: true });
|
||||
ctx.ui.notify(`Removed worktree ${name}.`, "info");
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Worktree partially removed: ${msg}\n\nRun 'git worktree prune' to clean up any dangling registrations.`,
|
||||
"error",
|
||||
|
|
@ -348,7 +349,7 @@ export async function handleWorktree(args, ctx) {
|
|||
"warning",
|
||||
);
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Worktree command failed: ${msg}`, "error");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ import { handleQuick } from "../../quick.js";
|
|||
import { createRun, listRuns } from "../../run-manager.js";
|
||||
import { deriveState } from "../../state.js";
|
||||
import { projectRoot } from "../context.js";
|
||||
import { getErrorMessage } from "../../error-utils.js";
|
||||
|
||||
// ─── Custom Workflow Subcommands ─────────────────────────────────────────
|
||||
const WORKFLOW_USAGE = [
|
||||
|
|
@ -136,7 +137,7 @@ async function handleCustomWorkflow(sub, ctx, pi) {
|
|||
// Clean up engine state so a failed workflow run doesn't pollute the next /autonomous
|
||||
setActiveEngineId(null);
|
||||
setActiveRunDir(null);
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to run workflow "${defName}": ${msg}`, "error");
|
||||
}
|
||||
return true;
|
||||
|
|
@ -184,7 +185,7 @@ async function handleCustomWorkflow(sub, ctx, pi) {
|
|||
);
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
ctx.ui.notify(`Failed to validate "${defName}": ${msg}`, "error");
|
||||
}
|
||||
return true;
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { parse } from "yaml";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
/** Read and parse the frozen DEFINITION.yaml from a run directory. */
|
||||
export function readFrozenDefinition(runDir) {
|
||||
const defPath = join(runDir, "DEFINITION.yaml");
|
||||
|
|
@ -14,7 +15,7 @@ export function readFrozenDefinition(runDir) {
|
|||
const raw = readFileSync(defPath, "utf-8");
|
||||
return parse(raw, { schema: "core" });
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
const wrapped = new Error(
|
||||
`Failed to read/parse DEFINITION.yaml at ${defPath}: ${message}`,
|
||||
{ cause: err },
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import {
|
|||
getWorktreeMode,
|
||||
loadEffectiveSFPreferences,
|
||||
} from "./preferences.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Check that all Tier 1.4 config keys are well-formed and within expected ranges.
|
||||
|
|
@ -253,7 +254,7 @@ export async function checkConfigHealth(issues, fixesApplied, shouldFix) {
|
|||
code: "config_check_error",
|
||||
scope: "project",
|
||||
unitId: "config",
|
||||
message: `Config health check failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
message: `Config health check failed: ${getErrorMessage(err)}`,
|
||||
file: ".sf/preferences.yaml",
|
||||
fixable: false,
|
||||
});
|
||||
|
|
@ -360,7 +361,7 @@ export function checkVaultHealth(issues, _shouldFix) {
|
|||
code: "vault_unreachable",
|
||||
scope: "project",
|
||||
unitId: "vault",
|
||||
message: `Vault at ${vaultAddr} is unreachable (${err instanceof Error ? err.message : String(err)}). This is OK if vault is not yet set up.`,
|
||||
message: `Vault at ${vaultAddr} is unreachable (${getErrorMessage(err)}). This is OK if vault is not yet set up.`,
|
||||
file: "vault server",
|
||||
fixable: false,
|
||||
});
|
||||
|
|
@ -372,7 +373,7 @@ export function checkVaultHealth(issues, _shouldFix) {
|
|||
code: "vault_check_error",
|
||||
scope: "project",
|
||||
unitId: "vault",
|
||||
message: `Vault health check failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
message: `Vault health check failed: ${getErrorMessage(err)}`,
|
||||
file: ".sf/preferences.yaml",
|
||||
fixable: false,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import {
|
|||
import { extractVerdict } from "./verdict-parser.js";
|
||||
import { readEvents } from "./workflow-events.js";
|
||||
import { renderAllProjections } from "./workflow-projections.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const LEGACY_MILESTONE_DIR_RE = /^(M\d+)-.+$/;
|
||||
const LEGACY_SLICE_DIR_RE = /^(S\d+)-.+$/;
|
||||
|
|
@ -118,7 +119,7 @@ function projectionDriftIssues(basePath, milestoneId) {
|
|||
code: "db_projection_roadmap_invalid",
|
||||
scope: "milestone",
|
||||
unitId: milestoneId,
|
||||
message: `${milestoneId}-ROADMAP.json could not be parsed: ${err instanceof Error ? err.message : String(err)}. Projection is not executable runtime state.`,
|
||||
message: `${milestoneId}-ROADMAP.json could not be parsed: ${getErrorMessage(err)}. Projection is not executable runtime state.`,
|
||||
file: roadmapJsonPath,
|
||||
fixable: false,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ import { getMilestoneSlices, getSliceTasks, isDbAvailable } from "./sf-db.js";
|
|||
import { deriveState, isMilestoneComplete } from "./state.js";
|
||||
import { isClosedStatus } from "./status-guards.js";
|
||||
import { parseUnitId } from "./unit-id.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
// ─── Flow Audit Implementation ────────────────────────────────────────────
|
||||
const DEFAULT_STALE_PROGRESS_MS = 20 * 60 * 1000;
|
||||
|
|
@ -814,7 +815,7 @@ export async function runFlowAudit(basePath, options = {}) {
|
|||
else process.kill(row.pid, "SIGTERM");
|
||||
killed = true;
|
||||
} catch (err) {
|
||||
killError = err instanceof Error ? err.message : String(err);
|
||||
killError = getErrorMessage(err);
|
||||
warnings.push(
|
||||
`Failed to kill over-budget ${classification} child pid ${row.pid}: ${killError}`,
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { pathToFileURL } from "node:url";
|
|||
import { getAgentDir } from "@singularity-forge/coding-agent";
|
||||
import { logWarning } from "../workflow-logger.js";
|
||||
import { createSFExtensionAPI } from "./sf-extension-api.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
// ─── Trust check (inlined; pi does not export isProjectTrusted from its
|
||||
// package root, and constraint forbids modifying packages/coding-agent/) ─
|
||||
|
|
@ -78,7 +79,7 @@ async function _loadEcosystemExtensionsImpl(pi, sharedHandlers, cwd) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"ecosystem",
|
||||
`failed to resolve extensions dir: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`failed to resolve extensions dir: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -91,7 +92,7 @@ async function _loadEcosystemExtensionsImpl(pi, sharedHandlers, cwd) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"ecosystem",
|
||||
`failed to read extensions dir: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`failed to read extensions dir: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -111,7 +112,7 @@ async function _loadOne(extDir, realExtDir, entry, api) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"ecosystem",
|
||||
`failed to resolve ${entry}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`failed to resolve ${entry}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -149,7 +150,7 @@ async function _loadOne(extDir, realExtDir, entry, api) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"ecosystem",
|
||||
`failed to import ${entry}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`failed to import ${entry}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
|
@ -163,7 +164,7 @@ async function _loadOne(extDir, realExtDir, entry, api) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"ecosystem",
|
||||
`factory threw for ${entry}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`factory threw for ${entry}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
import { Type } from "@sinclair/typebox";
|
||||
import { Value } from "@sinclair/typebox/value";
|
||||
import { parse as parseYaml } from "yaml";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
// ─── Constants ────────────────────────────────────────────────────────────────
|
||||
/** Schema version literal embedded in every EVAL-REVIEW.md frontmatter. */
|
||||
export const EVAL_REVIEW_SCHEMA_VERSION = "eval-review/v1";
|
||||
|
|
@ -143,7 +144,7 @@ export function parseEvalReviewFrontmatter(raw) {
|
|||
try {
|
||||
parsed = parseYaml(fm.yaml, { schema: "core" });
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
return { ok: false, error: `YAML parse error: ${msg}`, pointer: "/" };
|
||||
}
|
||||
const schema = EvalReviewFrontmatter;
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { spawn } from "node:child_process";
|
|||
import { randomUUID } from "node:crypto";
|
||||
import { existsSync, mkdirSync, writeFileSync } from "node:fs";
|
||||
import { resolve } from "node:path";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const ALWAYS_FORWARD_ENV = ["PATH", "HOME"];
|
||||
export const EXEC_DEFAULTS = {
|
||||
|
|
@ -96,7 +97,7 @@ export function runExecSandbox(request, opts) {
|
|||
});
|
||||
} catch (err) {
|
||||
const duration = Date.now() - started;
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
writeFileSync(stdoutPath, "");
|
||||
writeFileSync(stderrPath, `spawn error: ${message}\n`);
|
||||
const result = {
|
||||
|
|
@ -217,7 +218,7 @@ export function runExecSandbox(request, opts) {
|
|||
resolveP(result);
|
||||
};
|
||||
child.on("error", (err) => {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
const line = `child error: ${message}\n`;
|
||||
const remaining = opts.stderr_cap_bytes - stderrBytes;
|
||||
if (remaining > 0) {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import { appendEvent } from "./workflow-events.js";
|
|||
import { logWarning } from "./workflow-logger.js";
|
||||
import { writeManifest } from "./workflow-manifest.js";
|
||||
import { renderAllProjections } from "./workflow-projections.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const REPO_INSTRUCTION_FILES = [
|
||||
"AGENTS.md",
|
||||
|
|
@ -116,7 +117,7 @@ export async function skipExecuteTaskForInstructionConflict(
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`instruction-conflict skip post-mutation hook warning: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`instruction-conflict skip post-mutation hook warning: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
invalidateStateCache();
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
let cachedGraphApi = null;
|
||||
let resolvedGraphApi = false;
|
||||
|
|
@ -170,7 +171,7 @@ export async function inlineGraphSubgraph(projectDir, term, opts) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"prompt",
|
||||
`inlineGraphSubgraph failed (non-fatal): ${err instanceof Error ? err.message : String(err)}`,
|
||||
`inlineGraphSubgraph failed (non-fatal): ${getErrorMessage(err)}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
// missing `pi` (e.g. in standalone unit tests) logs a warning so callers know
|
||||
// hooks won't fire, but never throws.
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
let _pi;
|
||||
let _missingPiWarningLogged = false;
|
||||
|
|
@ -40,7 +41,7 @@ async function emitEvent(event) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"hook",
|
||||
`emitExtensionEvent failed for ${event.type}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`emitExtensionEvent failed for ${event.type}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return undefined;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { getErrorMessage } from "./error-utils.js";
|
||||
export {
|
||||
clearPendingGate,
|
||||
getPendingGate,
|
||||
|
|
@ -37,7 +38,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"bootstrap",
|
||||
`Extension setup partially failed — SF commands are available but shortcuts/tools may be missing: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Extension setup partially failed — SF commands are available but shortcuts/tools may be missing: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -52,7 +53,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"subagent",
|
||||
`SF subagent setup failed — delegation tools may be missing: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`SF subagent setup failed — delegation tools may be missing: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -66,7 +67,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"ui",
|
||||
`SF TUI setup failed — running with default header/footer: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`SF TUI setup failed — running with default header/footer: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -78,7 +79,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"usage-bar",
|
||||
`SF usage bar setup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`SF usage bar setup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -92,7 +93,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"notifications",
|
||||
`SF notifications setup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`SF notifications setup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -106,7 +107,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"inturn-guard",
|
||||
`SF in-turn guard setup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`SF in-turn guard setup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -120,7 +121,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"permissions",
|
||||
`SF permissions setup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`SF permissions setup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -134,7 +135,7 @@ export default async function registerExtension(pi) {
|
|||
const { logWarning } = await import("./workflow-logger.js");
|
||||
logWarning(
|
||||
"legacy-commands",
|
||||
`SF legacy commands setup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`SF legacy commands setup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ import { logWarning } from "../workflow-logger.js";
|
|||
import { createBeforeModelSelectHandler } from "./hook-handler.mjs";
|
||||
import { loadCapabilityOverrides } from "./loadCapabilityOverrides.mjs";
|
||||
import { validateOutcome } from "./outcome-recorder.mjs";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const DEFAULT_N_PRIOR = 10;
|
||||
const DEFAULT_ROLLING_DAYS = 30;
|
||||
|
|
@ -45,7 +46,7 @@ async function ensureLearningReady() {
|
|||
cachedDb = null;
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`failed to initialize learned routing: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`failed to initialize learned routing: ${getErrorMessage(err)}`,
|
||||
);
|
||||
} finally {
|
||||
initPromise = null;
|
||||
|
|
@ -75,7 +76,7 @@ export function recordLearnedOutcome(input) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"db",
|
||||
`failed to record learned routing outcome: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`failed to record learned routing outcome: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
*/
|
||||
|
||||
import { flushSyncQueue } from "./sync-scheduler.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Flush SM sync queue for a project before unit completes.
|
||||
|
|
@ -36,7 +37,7 @@ export async function flushProjectMemorySync(projectId) {
|
|||
failed: 0,
|
||||
elapsed,
|
||||
status: "error",
|
||||
reason: err instanceof Error ? err.message : String(err),
|
||||
reason: getErrorMessage(err),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ import {
|
|||
import { dirname, join } from "node:path";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { sfHome } from "./sf-home.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
/**
|
||||
* Bump `FLOW_VERSION` whenever a new required step is added to ONBOARDING_STEPS.
|
||||
* Records with an older flowVersion are treated as "needs partial re-onboarding"
|
||||
|
|
@ -94,7 +95,7 @@ export function writeOnboardingRecord(patch) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"state",
|
||||
`Failed to persist onboarding record: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Failed to persist onboarding record: ${getErrorMessage(err)}`,
|
||||
{
|
||||
file: FILE,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import {
|
|||
worktreePath,
|
||||
worktreesDir,
|
||||
} from "./worktree-manager.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
// ─── Internal Helpers ─────────────────────────────────────────────────────────
|
||||
/**
|
||||
|
|
@ -95,7 +96,7 @@ export function sweepOrphanWorktrees(basePath) {
|
|||
} catch (err) {
|
||||
result.errors.push({
|
||||
id: "<worktrees-dir>",
|
||||
reason: `readdirSync failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
reason: `readdirSync failed: ${getErrorMessage(err)}`,
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
|
@ -156,7 +157,7 @@ export function sweepOrphanWorktrees(basePath) {
|
|||
} catch (err) {
|
||||
result.errors.push({
|
||||
id,
|
||||
reason: err instanceof Error ? err.message : String(err),
|
||||
reason: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { dirname, join } from "node:path";
|
|||
import { parse as parseYaml, stringify as stringifyYaml } from "yaml";
|
||||
import { sfRoot } from "./paths.js";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Resolve the path to the project-level preferences file.
|
||||
|
|
@ -75,7 +76,7 @@ function readProjectPreferencesParts(path) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"guided",
|
||||
`preferences.yaml has invalid YAML — rewriting: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`preferences.yaml has invalid YAML — rewriting: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ import { nativeHasStagedChanges } from "./native-git-bridge.js";
|
|||
import { sfRoot } from "./paths.js";
|
||||
import { loadEffectiveSFPreferences } from "./preferences.js";
|
||||
import { loadPrompt } from "./prompt-loader.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
let pendingQuickReturn = null;
|
||||
// ─── Quick Task Helpers ───────────────────────────────────────────────────────
|
||||
|
|
@ -191,7 +192,7 @@ export async function handleQuick(args, ctx, pi) {
|
|||
}
|
||||
} catch (err) {
|
||||
// Branch creation failed — continue on current branch
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
ctx.ui.notify(
|
||||
`Could not create branch ${branchName}: ${message}. Working on current branch.`,
|
||||
"warning",
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import { dirname, join } from "node:path";
|
|||
import { SCAFFOLD_FILES } from "./agentic-docs-scaffold.js";
|
||||
import { detectScaffoldDrift } from "./scaffold-drift.js";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Build the .proposed body shipped by the Phase-D stub: the current scaffold
|
||||
|
|
@ -135,7 +136,7 @@ export function dispatchScaffoldKeeperFireAndForget(basePath, ctx) {
|
|||
queueMicrotask(() => {
|
||||
dispatchScaffoldKeeperIfNeeded(basePath, ctx).catch((err) => {
|
||||
logWarning("scaffold", "scaffold-keeper dispatch threw", {
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -41,6 +41,7 @@ import {
|
|||
} from "../task-frontmatter.js";
|
||||
import { readTraceEvents } from "../uok/trace-writer.js";
|
||||
import { logError, logWarning } from "../workflow-logger.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
let loadAttempted = false;
|
||||
function loadProvider() {
|
||||
|
|
@ -207,7 +208,7 @@ function createDatabaseSnapshot(rawDb, path) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"sf-db",
|
||||
`database snapshot failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`database snapshot failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -242,7 +243,7 @@ function performDatabaseMaintenance(rawDb, path) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"sf-db",
|
||||
`database maintenance failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`database maintenance failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ import {
|
|||
emitMilestoneResquash,
|
||||
emitSliceMerged,
|
||||
} from "./worktree-telemetry.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Auto-worktree milestone branch name. Must match autoWorktreeBranch() in
|
||||
|
|
@ -56,7 +57,7 @@ function cleanupMergeArtifacts(projectRoot) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"worktree",
|
||||
`merge artifact cleanup failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`merge artifact cleanup failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
* Tries to connect to SM at SINGULARITY_MEMORY_ADDR (default: http://localhost:8080).
|
||||
* SM is opt-in: set SM_ENABLED=true to activate. Disabled by default.
|
||||
*/
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
export async function initializeSmClient() {
|
||||
// SM is opt-in — disabled unless explicitly enabled
|
||||
if (process.env.SM_ENABLED !== "true") {
|
||||
|
|
@ -56,7 +57,7 @@ export async function initializeSmClient() {
|
|||
return {
|
||||
connected: false,
|
||||
version: null,
|
||||
reason: `SM unreachable at ${addr}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
reason: `SM unreachable at ${addr}: ${getErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -111,7 +112,7 @@ export async function syncMemoryToSm(memory, opts = {}) {
|
|||
}
|
||||
} catch (err) {
|
||||
console.warn(
|
||||
`[sm-client] Error syncing memory ${memory.id}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`[sm-client] Error syncing memory ${memory.id}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@
|
|||
import { existsSync } from "node:fs";
|
||||
import { join } from "node:path";
|
||||
import { DatabaseSync } from "node:sqlite";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
const SPEC_GENERATOR_VERSION = "1";
|
||||
|
||||
|
|
@ -51,7 +52,7 @@ function readDbSummary(basePath) {
|
|||
`- DB spec rows: milestone_specs=${milestoneSpecs}, slice_specs=${sliceSpecs}, task_specs=${taskSpecs}`,
|
||||
].join("\n");
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
return `- Database state: unreadable (${message})`;
|
||||
} finally {
|
||||
db?.close();
|
||||
|
|
|
|||
|
|
@ -1,4 +1,5 @@
|
|||
import { randomUUID } from "node:crypto";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
export class SubagentBackgroundJobManager {
|
||||
jobs = new Map();
|
||||
evictionTimers = new Map();
|
||||
|
|
@ -60,7 +61,7 @@ export class SubagentBackgroundJobManager {
|
|||
return;
|
||||
}
|
||||
job.status = "failed";
|
||||
job.errorText = err instanceof Error ? err.message : String(err);
|
||||
job.errorText = getErrorMessage(err);
|
||||
this.scheduleEviction(job.id);
|
||||
this.deliverResult(job);
|
||||
});
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import * as fs from "node:fs";
|
|||
import * as path from "node:path";
|
||||
import { promisify } from "node:util";
|
||||
import { sfHome } from "../sf-home.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const execFile = promisify(execFileCb);
|
||||
// ============================================================================
|
||||
|
|
@ -356,7 +357,7 @@ export async function mergeDeltaPatches(repoRoot, patches) {
|
|||
success: false,
|
||||
appliedPatches,
|
||||
failedPatches,
|
||||
error: `Patch conflict: ${err instanceof Error ? err.message : String(err)}`,
|
||||
error: `Patch conflict: ${getErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
// Apply for real
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
import { delay } from "./atomic-write.js";
|
||||
import { syncMemoryToSm } from "./sm-client.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* Global sync scheduler state.
|
||||
|
|
@ -201,7 +202,7 @@ async function trySyncWithRetry(item, attempt = 0) {
|
|||
if (typeof process !== "undefined" && process.env.DEBUG_SM_SYNC) {
|
||||
console.warn(
|
||||
`[SM sync] failed after ${MAX_RETRIES} retries: ${item.id}`,
|
||||
err instanceof Error ? err.message : String(err),
|
||||
getErrorMessage(err),
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@
|
|||
import { EXEC_DEFAULTS, runExecSandbox } from "../exec-sandbox.js";
|
||||
import { isContextModeEnabled } from "../preferences-types.js";
|
||||
import { sanitizeExternalContent } from "../safety/sanitize-external-content.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
export function buildExecOptions(baseDir, cfg, extras) {
|
||||
const allowlist = Array.isArray(cfg?.exec_env_allowlist)
|
||||
? cfg.exec_env_allowlist
|
||||
|
|
@ -111,7 +112,7 @@ export async function executeSfExec(params, deps) {
|
|||
);
|
||||
return formatResult(result);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
return {
|
||||
content: [
|
||||
{ type: "text", text: `Error: run_command failed — ${message}` },
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ import {
|
|||
resolveSiftSearchScope,
|
||||
} from "../code-intelligence.js";
|
||||
import { recordRetrievalEvidence } from "../retrieval-evidence.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const _KNOWN_STRATEGIES = [
|
||||
"hybrid",
|
||||
|
|
@ -344,7 +345,7 @@ export function registerSiftSearchTool(pi) {
|
|||
};
|
||||
} catch (err) {
|
||||
const elapsedMs = Date.now() - startedAt;
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
await recordRetrievalEvidence(projectRoot, {
|
||||
backend: "sift",
|
||||
sourceKind: "code",
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import { handlePlanSlice } from "./plan-slice.js";
|
|||
import { handleReassessRoadmap } from "./reassess-roadmap.js";
|
||||
import { handleReplanSlice } from "./replan-slice.js";
|
||||
import { handleValidateMilestone } from "./validate-milestone.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
export const SUPPORTED_SUMMARY_ARTIFACT_TYPES = [
|
||||
"SUMMARY",
|
||||
"RESEARCH",
|
||||
|
|
@ -180,7 +181,7 @@ export async function executeSummarySave(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `save_summary tool failed: ${msg}`, {
|
||||
tool: "save_summary",
|
||||
error: String(err),
|
||||
|
|
@ -269,7 +270,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|||
} catch (err) {
|
||||
// Escalation is additive — never block task completion if it fails,
|
||||
// but DO tell the agent so they don't think the issue was recorded.
|
||||
escalationError = err instanceof Error ? err.message : String(err);
|
||||
escalationError = getErrorMessage(err);
|
||||
logError(
|
||||
"tool",
|
||||
`complete_task escalation write failed: ${escalationError}`,
|
||||
|
|
@ -303,7 +304,7 @@ export async function executeTaskComplete(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `complete_task tool failed: ${msg}`, {
|
||||
tool: "complete_task",
|
||||
error: String(err),
|
||||
|
|
@ -401,7 +402,7 @@ export async function executeSliceComplete(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `complete_slice tool failed: ${msg}`, {
|
||||
tool: "complete_slice",
|
||||
error: String(err),
|
||||
|
|
@ -456,7 +457,7 @@ export async function executeCompleteMilestone(
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `complete_milestone tool failed: ${msg}`, {
|
||||
tool: "complete_milestone",
|
||||
error: String(err),
|
||||
|
|
@ -511,7 +512,7 @@ export async function executeValidateMilestone(
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `validate_milestone tool failed: ${msg}`, {
|
||||
tool: "validate_milestone",
|
||||
error: String(err),
|
||||
|
|
@ -564,7 +565,7 @@ export async function executeReassessRoadmap(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `reassess_roadmap tool failed: ${msg}`, {
|
||||
tool: "reassess_roadmap",
|
||||
error: String(err),
|
||||
|
|
@ -654,7 +655,7 @@ export async function executeSaveGateResult(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `record_gate failed: ${msg}`, {
|
||||
tool: "record_gate",
|
||||
error: String(err),
|
||||
|
|
@ -709,7 +710,7 @@ export async function executePlanMilestone(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `plan_milestone tool failed: ${msg}`, {
|
||||
tool: "plan_milestone",
|
||||
error: String(err),
|
||||
|
|
@ -762,7 +763,7 @@ export async function executePlanSlice(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `plan_slice tool failed: ${msg}`, {
|
||||
tool: "plan_slice",
|
||||
error: String(err),
|
||||
|
|
@ -815,7 +816,7 @@ export async function executeReplanSlice(params, basePath = process.cwd()) {
|
|||
},
|
||||
};
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logError("tool", `replan_slice tool failed: ${msg}`, {
|
||||
tool: "replan_slice",
|
||||
error: String(err),
|
||||
|
|
@ -881,7 +882,7 @@ export async function executeMilestoneStatus(params, basePath = process.cwd()) {
|
|||
};
|
||||
});
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
logWarning("tool", `milestone_status tool failed: ${msg}`);
|
||||
return {
|
||||
content: [
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@ import {
|
|||
pushPromptHistory,
|
||||
readPromptHistory,
|
||||
} from "./prompt-history.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const WORK_MODE_CYCLE = [
|
||||
"chat",
|
||||
|
|
@ -487,7 +488,7 @@ export default function sfTui(pi) {
|
|||
return { output: response };
|
||||
} catch (err) {
|
||||
return {
|
||||
output: `Agent dispatch failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
output: `Agent dispatch failed: ${getErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
},
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@ import {
|
|||
} from "@a2a-js/sdk/server/express";
|
||||
import express from "express";
|
||||
import { buildAgentCard } from "./a2a-transport.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const agentName = process.env.SF_A2A_AGENT_NAME;
|
||||
const agentRole = process.env.SF_A2A_AGENT_ROLE ?? "worker";
|
||||
|
|
@ -103,7 +104,7 @@ class SwarmAgentExecutor {
|
|||
resultBody = await this._handleEnvelope(envelope);
|
||||
} catch (err) {
|
||||
resultBody = {
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
agentName: this._name,
|
||||
role: this._role,
|
||||
unitId: envelope?.unitId,
|
||||
|
|
|
|||
|
|
@ -184,7 +184,7 @@ function hasPriorParallelResearchFailure(basePath, mid) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`Ignoring unreadable parallel-research runtime state for ${mid}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Ignoring unreadable parallel-research runtime state for ${mid}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return false;
|
||||
}
|
||||
|
|
@ -1576,7 +1576,7 @@ export const DISPATCH_RULES = [
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`failed to persist validation attention marker: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`failed to persist validation attention marker: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return {
|
||||
|
|
@ -1696,7 +1696,7 @@ export const DISPATCH_RULES = [
|
|||
/* fall through — don't block on DB errors */
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`verification class check failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`verification class check failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
// P5-A: Advisory check for deferred requirements targeting this milestone
|
||||
|
|
@ -1915,6 +1915,7 @@ export const DISPATCH_RULES = [
|
|||
];
|
||||
|
||||
import { getRegistry, hasRegistry } from "../rule-registry.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
// ─── Dispatch Envelope Emission ───────────────────────────────────────────
|
||||
/**
|
||||
|
|
@ -2027,7 +2028,7 @@ export async function resolveDispatch(ctx) {
|
|||
// surface real bugs, then fall back.
|
||||
logWarning(
|
||||
"dispatch",
|
||||
`registry dispatch failed, falling back to inline rules: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`registry dispatch failed, falling back to inline rules: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { snapshotUnitMetrics } from "../metrics.js";
|
|||
import { updateSubscriptionTokensUsed } from "../preferences-models.js";
|
||||
import { logWarning } from "../workflow-logger.js";
|
||||
import { writeTurnGitTransaction } from "./gitops.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
/**
|
||||
* Snapshot metrics, save activity log, and fire-and-forget memory extraction
|
||||
* for a completed unit. Returns the activity log file path (if any).
|
||||
|
|
@ -60,7 +61,7 @@ export async function closeoutUnit(
|
|||
/* non-fatal */
|
||||
logWarning(
|
||||
"engine",
|
||||
`operation failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`operation failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -45,6 +45,7 @@ import {
|
|||
formatExecuteTaskRecoveryStatus,
|
||||
inspectExecuteTaskDurability,
|
||||
} from "./unit-runtime.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
function computeTokenCountFromSession(ctx) {
|
||||
const entries = ctx.sessionManager?.getEntries?.() ?? [];
|
||||
|
|
@ -353,7 +354,7 @@ export async function runPostUnitVerification(vctx, pauseAuto) {
|
|||
.catch((err) => ({
|
||||
outcome: "fail",
|
||||
failureClass: "unknown",
|
||||
rationale: `Gate ${id} threw: ${err instanceof Error ? err.message : String(err)}`,
|
||||
rationale: `Gate ${id} threw: ${getErrorMessage(err)}`,
|
||||
})),
|
||||
),
|
||||
);
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|||
import { tmpdir } from "node:os";
|
||||
import { join } from "node:path";
|
||||
import { delay } from "../atomic-write.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const DEFAULT_LATENCY_PROBABILITY = 0.05;
|
||||
const DEFAULT_PARTIAL_FAILURE_PROBABILITY = 0.03;
|
||||
|
|
@ -39,7 +40,7 @@ export class ChaosMonkeyGate {
|
|||
return {
|
||||
outcome: "fail",
|
||||
failureClass: "execution",
|
||||
rationale: `Chaos monkey injected fault: ${err instanceof Error ? err.message : String(err)}`,
|
||||
rationale: `Chaos monkey injected fault: ${getErrorMessage(err)}`,
|
||||
findings: `Injected during verification phase (attempt ${attempt})`,
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ import { logWarning } from "../workflow-logger.js";
|
|||
import { buildAuditEnvelope, emitUokAuditEvent } from "./audit.js";
|
||||
import { validateGate } from "./contracts.js";
|
||||
import { appendTraceEvent } from "./trace-writer.js";
|
||||
import { getErrorMessage } from "../error-utils.js";
|
||||
|
||||
const RETRY_MATRIX = {
|
||||
none: 0,
|
||||
|
|
@ -112,7 +113,7 @@ export async function enrichGateResultWithMemory(gateResult, gateId) {
|
|||
// Degrade gracefully - memory enrichment never changes gate result
|
||||
logWarning(
|
||||
"gate-runner",
|
||||
`Memory enrichment failed for gate ${gateId}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Memory enrichment failed for gate ${gateId}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -392,7 +393,7 @@ export class UokGateRunner {
|
|||
try {
|
||||
result = await gate.execute(ctx, attempt);
|
||||
} catch (err) {
|
||||
const message = err instanceof Error ? err.message : String(err);
|
||||
const message = getErrorMessage(err);
|
||||
result = {
|
||||
outcome: "fail",
|
||||
failureClass: "unknown",
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@
|
|||
import { existsSync, readFileSync } from "node:fs";
|
||||
import { homedir } from "node:os";
|
||||
import { logWarning } from "./workflow-logger.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
/**
|
||||
* In-memory cache for resolved vault secrets.
|
||||
|
|
@ -67,7 +68,7 @@ export function parseVaultUri(uri) {
|
|||
return { path, field, vaultAddr, token };
|
||||
} catch (err) {
|
||||
return {
|
||||
error: `Failed to parse vault URI: ${err instanceof Error ? err.message : String(err)}`,
|
||||
error: `Failed to parse vault URI: ${getErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -140,7 +141,7 @@ async function fetchVaultSecret(path, vaultAddr, token) {
|
|||
// Log error but don't throw — fail open
|
||||
logWarning(
|
||||
"vault-resolver",
|
||||
`Vault fetch failed for ${path}: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Vault fetch failed for ${path}: ${getErrorMessage(err)}`,
|
||||
);
|
||||
return null;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import { sfHome } from './sf-home.js';
|
|||
import { extname, join, sep as pathSep, resolve } from "node:path";
|
||||
import { parse as parseYaml } from "yaml";
|
||||
import { validateDefinition } from "./definition-loader.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
// ─── Constants ───────────────────────────────────────────────────────────
|
||||
const MAX_RESPONSE_BYTES = 256 * 1024;
|
||||
|
|
@ -212,7 +213,7 @@ export function validateFetchedContent(fetched) {
|
|||
parsed = parseYaml(fetched.content);
|
||||
} catch (err) {
|
||||
throw new Error(
|
||||
`Installed YAML failed to parse: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`Installed YAML failed to parse: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
const result = validateDefinition(parsed);
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { sfHome } from './sf-home.js';
|
|||
import { basename, extname, join } from "node:path";
|
||||
import { parse as parseYaml } from "yaml";
|
||||
import { loadRegistry } from "./workflow-templates.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
|
||||
// ─── Path resolution ─────────────────────────────────────────────────────
|
||||
function resolveBundledDir() {
|
||||
|
|
@ -143,7 +144,7 @@ function loadYamlPlugin(filePath, source) {
|
|||
format: "yaml",
|
||||
source,
|
||||
meta: { displayName: name, mode: "yaml-step" },
|
||||
error: `YAML parse error: ${err instanceof Error ? err.message : String(err)}`,
|
||||
error: `YAML parse error: ${getErrorMessage(err)}`,
|
||||
};
|
||||
}
|
||||
if (parsed == null || typeof parsed !== "object") {
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ import {
|
|||
emitCanonicalRootRedirect,
|
||||
emitWorktreeDivergenceWarning,
|
||||
} from "./worktree-telemetry.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
/** Commits-behind threshold above which a divergence warning is emitted. */
|
||||
export const WORKTREE_DIVERGENCE_CAP = 50;
|
||||
// ─── Path Helpers ──────────────────────────────────────────────────────────
|
||||
|
|
@ -147,7 +148,7 @@ export function resolveCanonicalMilestoneRoot(basePath, milestoneId) {
|
|||
} catch (err) {
|
||||
logWarning(
|
||||
"worktree",
|
||||
`canonical-root-redirect telemetry failed: ${err instanceof Error ? err.message : String(err)}`,
|
||||
`canonical-root-redirect telemetry failed: ${getErrorMessage(err)}`,
|
||||
);
|
||||
}
|
||||
return wtPath;
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@ import {
|
|||
resquashMilestoneOnMain,
|
||||
} from "./slice-cadence.js";
|
||||
import { resolveGitDir } from "./worktree-manager.js";
|
||||
import { getErrorMessage } from "./error-utils.js";
|
||||
import {
|
||||
emitWorktreeCreated,
|
||||
emitWorktreeMerged,
|
||||
|
|
@ -165,7 +166,7 @@ export class WorktreeResolver {
|
|||
});
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
debugLog("WorktreeResolver", {
|
||||
action: "enterMilestone",
|
||||
milestoneId,
|
||||
|
|
@ -219,7 +220,7 @@ export class WorktreeResolver {
|
|||
action: "exitMilestone",
|
||||
milestoneId,
|
||||
phase: "auto-commit-failed",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
try {
|
||||
|
|
@ -231,7 +232,7 @@ export class WorktreeResolver {
|
|||
action: "exitMilestone",
|
||||
milestoneId,
|
||||
phase: "teardown-failed",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
this.restoreToProjectRoot();
|
||||
|
|
@ -355,7 +356,7 @@ export class WorktreeResolver {
|
|||
action: "mergeAndExit",
|
||||
milestoneId,
|
||||
phase: "resquash",
|
||||
error: err instanceof Error ? err.message : String(err),
|
||||
error: getErrorMessage(err),
|
||||
});
|
||||
}
|
||||
// #4764 — record merge completion. Only reaches here when an actual
|
||||
|
|
@ -481,7 +482,7 @@ export class WorktreeResolver {
|
|||
);
|
||||
}
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
debugLog("WorktreeResolver", {
|
||||
action: "mergeAndExit",
|
||||
milestoneId,
|
||||
|
|
@ -604,7 +605,7 @@ export class WorktreeResolver {
|
|||
});
|
||||
return true;
|
||||
} catch (err) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
const msg = getErrorMessage(err);
|
||||
debugLog("WorktreeResolver", {
|
||||
action: "mergeAndExit",
|
||||
milestoneId,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue