Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .mulch/expertise/patterns.jsonl
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"type":"pattern","classification":"tactical","recorded_at":"2026-06-15T10:37:47.637Z","evidence":{"commit":"e68a2ae9df420c2de7d30026727396d6c265306f"},"dir_anchors":["src/commands"],"name":"safe-error-message","description":"Use 'err instanceof Error ? err.message : String(err)' instead of '(err as Error).message' in catch blocks to safely handle non-Error throws","files":[".mulch/mulch.config.yaml","src/commands/archive.ts","src/commands/compact.ts","src/commands/config.ts","src/commands/delete-domain.ts","src/commands/delete.ts","src/commands/diff.ts","src/commands/doctor.ts","src/commands/edit.ts","src/commands/learn.ts","src/commands/move.ts","src/commands/onboard.ts","src/commands/prime.ts","src/commands/query.ts","src/commands/rank.ts","src/commands/ready.ts","src/commands/restore.ts","src/commands/search.ts","src/commands/sync.ts","src/utils/config.ts"],"id":"mx-357d18"}
1 change: 1 addition & 0 deletions .mulch/mulch.config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ domains:
- failure
quality-gates: {}
refactoring: {}
patterns: {}
governance:
max_entries: 100
warn_entries: 150
Expand Down
6 changes: 3 additions & 3 deletions .seeds/issues.jsonl
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,11 @@
{"id":"mulch-ab79","title":"Add the canonical scripts/check-all.ts quiet runner copied byte-identical from templates/l5-toolkit/scripts/check-all.ts, with mulch's exported GATES manifest in the standard's order: lint, typecheck, check:agents, check:dups, check:deps, check:size, check:debt, check:coverage, check:ci-parity (last) -- note lint and typecheck must be ADDED to the manifest (they exist as scripts but are absent from the current && chain). Replace package.json check:all with `bun scripts/check-all.ts`, add `verify`: `bun run check:all`, and add scripts/check-all.test.ts. Confirm the quiet-output contract.","status":"closed","type":"task","priority":2,"plan_step_index":0,"description":"<!-- seeds:plan-backref:start -->\nStep 1 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:56:59.979Z","plan_id":"pl-237d","blocks":["mulch-c658","mulch-f16f"],"closedAt":"2026-06-12T05:56:59.979Z"}
{"id":"mulch-c658","title":"Add scripts/check-ci-parity.ts (with test) copied from templates/l5-toolkit/scripts, importing the GATES array from check-all.ts; add the check:ci-parity script as the final gate in the manifest. Reconcile any residual non-canonical gate name. Verify check:ci-parity passes against .github/workflows/ci.yml.","status":"closed","type":"task","priority":2,"plan_step_index":1,"description":"<!-- seeds:plan-backref:start -->\nStep 2 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:57:00.030Z","plan_id":"pl-237d","blocks":["mulch-c6f8","mulch-f16f"],"closedAt":"2026-06-12T05:57:00.030Z"}
{"id":"mulch-c6f8","title":"Wire .github/workflows/ci.yml to invoke the canonical gates (or `bun run check:all`) so the local manifest matches CI. Run `bun run check:all` and `bun run verify` green end-to-end with the quiet-output contract and a passing check:ci-parity.","status":"closed","type":"task","priority":2,"plan_step_index":2,"description":"<!-- seeds:plan-backref:start -->\nStep 3 of plan pl-237d.\n\nParent seed: mulch-f16f — Adopt canonical check:all standard\nPlan template: feature\nPlan approach: Swap the && chain for the canonical quiet runner with a GATES manifest in the standard's order (folding in the already-present lint and typecheck scripts), then add the generalized ci-parity gate and the verify alias. mulch has no UI…\n\nRun `sd plan show pl-237d` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-12T04:53:28.928Z","updatedAt":"2026-06-12T05:57:00.083Z","plan_id":"pl-237d","blocks":["mulch-f16f"],"closedAt":"2026-06-12T05:57:00.083Z"}
{"id":"mulch-e3e9","title":"nightwatch patrol: 2026-06-15","status":"open","type":"task","priority":3,"createdAt":"2026-06-15T10:08:07.957Z","updatedAt":"2026-06-15T10:28:34.748Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4","mulch-0768"]}
{"id":"mulch-e3e9","title":"nightwatch patrol: 2026-06-15","status":"open","type":"task","priority":3,"createdAt":"2026-06-15T10:08:07.957Z","updatedAt":"2026-06-15T10:38:05.028Z","labels":["patrol","nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-9465","mulch-a424","mulch-4dc4","mulch-0768"]}
{"id":"mulch-4ca6","title":"Canonicalize JSON `up_to_date` vs `upToDate` across upgrade/onboard output","status":"closed","type":"task","priority":3,"plan_step_index":0,"description":"<!-- seeds:plan-backref:start -->\nStep 1 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:18:09.429Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"closedAt":"2026-06-15T10:18:09.429Z","closeReason":"Landed in 49f3aef: ml upgrade --json now emits up_to_date (snake_case) to match ml onboard --json. Test + CHANGELOG updated. bun run verify 9/9 green."}
{"id":"mulch-fed1","title":"Dedupe local parseStrictPositiveInt/parseStrictNonNegativeNumber copies; import from src/utils/numeric-flags.ts","status":"closed","type":"task","priority":3,"plan_step_index":1,"description":"<!-- seeds:plan-backref:start -->\nStep 2 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:28:34.748Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"closedAt":"2026-06-15T10:28:34.748Z"}
{"id":"mulch-4bd0","title":"Replace `(err as Error).message` with `err instanceof Error ? err.message : String(err)` across src/commands and src/utils","status":"open","type":"task","priority":3,"plan_step_index":2,"description":"<!-- seeds:plan-backref:start -->\nStep 3 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]}
{"id":"mulch-4bd0","title":"Replace `(err as Error).message` with `err instanceof Error ? err.message : String(err)` across src/commands and src/utils","status":"closed","type":"task","priority":3,"plan_step_index":2,"description":"<!-- seeds:plan-backref:start -->\nStep 3 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:38:05.028Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"],"extensions":{"role":"pi","lastRunId":"run_ch27daacnb7q","lastRunAt":"2026-06-15T10:32:18.766Z"},"closedAt":"2026-06-15T10:38:05.028Z"}
{"id":"mulch-9465","title":"Fix path-segment boundary in src/utils/git.ts fileMatchesAny + add false-positive coverage","status":"open","type":"task","priority":2,"plan_step_index":3,"description":"<!-- seeds:plan-backref:start -->\nStep 4 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]}
{"id":"mulch-a424","title":"Unify JSON vs human error wording in src/commands/ready.ts unknown-domain branch","status":"open","type":"task","priority":3,"plan_step_index":4,"description":"<!-- seeds:plan-backref:start -->\nStep 5 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]}
{"id":"mulch-4dc4","title":"Backfill direct unit tests for src/utils/domain-rules.ts and src/utils/format-helpers.ts","status":"open","type":"task","priority":3,"plan_step_index":5,"description":"<!-- seeds:plan-backref:start -->\nStep 6 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:08:46.513Z","labels":["nightwatch"],"plan_id":"pl-b637","blocks":["mulch-0768","mulch-e3e9"]}
{"id":"mulch-0768","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":6,"description":"<!-- seeds:plan-backref:start -->\nStep 7 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:28:34.748Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-4bd0","mulch-9465","mulch-a424","mulch-4dc4"],"blocks":["mulch-e3e9"]}
{"id":"mulch-0768","title":"Release: run /release per .claude/commands/release.md","status":"open","type":"task","priority":3,"plan_step_index":6,"description":"<!-- seeds:plan-backref:start -->\nStep 7 of plan pl-b637.\n\nParent seed: mulch-e3e9 — nightwatch patrol: 2026-06-15\nPlan template: refactor\nPlan approach: One step per finding so each lands as an isolated PR. Independent steps (1, 2, 3, 4, 5, 6) run in parallel; the release step (7) batches them. Step 1 (JSON key canonicalization) and step 4 (suffix-boundary fix) are the only…\n\nRun `sd plan show pl-b637` for the full plan (context, alternatives, sibling steps, acceptance criteria).\n<!-- seeds:plan-backref:end -->","createdAt":"2026-06-15T10:08:46.513Z","updatedAt":"2026-06-15T10:38:05.028Z","labels":["nightwatch"],"plan_id":"pl-b637","blockedBy":["mulch-9465","mulch-a424","mulch-4dc4"],"blocks":["mulch-e3e9"]}
6 changes: 4 additions & 2 deletions src/commands/archive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -204,9 +204,11 @@ export function registerArchiveCommand(program: Command): void {
}
} else {
if (jsonMode) {
outputJsonError("archive", (err as Error).message);
outputJsonError("archive", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(
chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`),
);
}
}
process.exitCode = 1;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/compact.ts
Original file line number Diff line number Diff line change
Expand Up @@ -773,7 +773,7 @@ async function handleApply(
try {
indicesToRemove = resolveRecordIds(records, identifiers);
} catch (err) {
const msg = (err as Error).message;
const msg = err instanceof Error ? err.message : String(err);
if (jsonMode) {
outputJsonError("compact", msg);
} else {
Expand Down
10 changes: 6 additions & 4 deletions src/commands/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ export function registerConfigCommand(program: Command): void {
try {
cfg = await readConfig();
} catch (err) {
process.stderr.write(`${(err as Error).message}\n`);
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
process.exitCode = 1;
return;
}
Expand Down Expand Up @@ -72,7 +72,7 @@ export function registerConfigCommand(program: Command): void {
try {
await runConfigSet(path, value);
} catch (err) {
process.stderr.write(`${(err as Error).message}\n`);
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
process.exitCode = 1;
}
});
Expand All @@ -90,7 +90,7 @@ export function registerConfigCommand(program: Command): void {
try {
await runConfigUnset(path);
} catch (err) {
process.stderr.write(`${(err as Error).message}\n`);
process.stderr.write(`${err instanceof Error ? err.message : String(err)}\n`);
process.exitCode = 1;
}
});
Expand Down Expand Up @@ -119,7 +119,9 @@ async function runConfigSet(rawPath: string, rawValue: string): Promise<void> {
try {
parsedValue = yaml.load(rawValue);
} catch (err) {
throw new Error(`Invalid YAML for <value>: ${(err as Error).message}`);
throw new Error(
`Invalid YAML for <value>: ${err instanceof Error ? err.message : String(err)}`,
);
}

await withFileLock(configPath, async () => {
Expand Down
4 changes: 2 additions & 2 deletions src/commands/delete-domain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,9 +110,9 @@ export function registerDeleteDomainCommand(program: Command): void {
}
} else {
if (jsonMode) {
outputJsonError("delete-domain", (err as Error).message);
outputJsonError("delete-domain", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
}
}
process.exitCode = 1;
Expand Down
6 changes: 4 additions & 2 deletions src/commands/delete.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,9 +306,11 @@ export function registerDeleteCommand(program: Command): void {
}
} else {
if (jsonMode) {
outputJsonError("delete", (err as Error).message);
outputJsonError("delete", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(
chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`),
);
}
}
process.exitCode = 1;
Expand Down
4 changes: 2 additions & 2 deletions src/commands/diff.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,9 +190,9 @@ export function registerDiffCommand(program: Command): void {
}
} catch (err) {
if (jsonMode) {
outputJsonError("diff", (err as Error).message);
outputJsonError("diff", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
}
process.exitCode = 1;
}
Expand Down
2 changes: 1 addition & 1 deletion src/commands/doctor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@ async function checkConfig(cwd?: string): Promise<DoctorCheck> {
return {
name: "config",
status: "fail",
message: `Config error: ${(err as Error).message}`,
message: `Config error: ${err instanceof Error ? err.message : String(err)}`,
fixable: false,
details: [],
};
Expand Down
4 changes: 2 additions & 2 deletions src/commands/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -215,9 +215,9 @@ export function registerEditCommand(program: Command): void {
}
} else {
if (jsonMode) {
outputJsonError("edit", (err as Error).message);
outputJsonError("edit", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
}
}
process.exitCode = 1;
Expand Down
4 changes: 2 additions & 2 deletions src/commands/learn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,9 +169,9 @@ export function registerLearnCommand(program: Command): void {
console.log();
} catch (err) {
if (jsonMode) {
outputJsonError("learn", (err as Error).message);
outputJsonError("learn", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
}
process.exitCode = 1;
}
Expand Down
7 changes: 5 additions & 2 deletions src/commands/move.ts
Original file line number Diff line number Diff line change
Expand Up @@ -313,8 +313,11 @@ export function registerMoveCommand(program: Command): void {
if (jsonMode) outputJsonError("move", msg);
else console.error(chalk.red(`Error: ${msg}`));
} else {
if (jsonMode) outputJsonError("move", (err as Error).message);
else console.error(chalk.red(`Error: ${(err as Error).message}`));
if (jsonMode) outputJsonError("move", err instanceof Error ? err.message : String(err));
else
console.error(
chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`),
);
}
process.exitCode = 1;
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/onboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -364,9 +364,9 @@ export function registerOnboardCommand(program: Command): void {
await runOnboard({ ...options, jsonMode });
} catch (err) {
if (jsonMode) {
outputJsonError("onboard", (err as Error).message);
outputJsonError("onboard", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
}
process.exitCode = 1;
}
Expand Down
4 changes: 2 additions & 2 deletions src/commands/prime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -667,9 +667,9 @@ export function registerPrimeCommand(program: Command): void {
}
} else {
if (jsonMode) {
outputJsonError("prime", (err as Error).message);
outputJsonError("prime", err instanceof Error ? err.message : String(err));
} else {
console.error(chalk.red(`Error: ${(err as Error).message}`));
console.error(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}`));
}
}
process.exitCode = 1;
Expand Down
Loading
Loading