🛡️ dsh-startup-guard
Boot-time guard for DeepSeek Harness — repairs session logs, preflights the plugin composition, smoke-tests host apply(), and quarantines crash sources before boot, so a broken plugin or corrupt log can never brick startup.
Overview
DSH is assembled from many third-party plugins: a missing package, a malformed patch, an unbuilt client artifact, or even a runtime exception thrown from a host apply() can crash the whole app at startup. dsh-startup-guard runs seven checks early in boot and can auto-repair / roll back / quarantine the source of the problem — it is a four-layer defense: parse → compose → execute → crash-containment, not just a set of file checks.
Zero configuration needed; typical overhead < 0.5s per boot.
Core capabilities
Quick start
dsh plugin --profile web add dsh-startup-guard # npm (prebuilt, skips build approval)
# or from source:
dsh plugin --profile web add github:aokamoaki/dsh-startup-guard
Published on npm: dsh-startup-guard@1.0.0 (npm page).
Restart dsh web. On first boot it scans/repairs sessions, snapshots the plugin manifests, smokes every third-party host entry, and writes the summary to ~/.dsh/dsh-preflight-report.json.
Modes & configuration
File: ~/.dsh/dsh-startup-guard.json (defaults when absent).
{
"mode": "fix",
"smoke": true,
"smokeTimeoutMs": 15000,
"clientVmCheck": true,
"clientFactorySmoke": false,
"quarantineOnCrash": true,
"autoRepairComposition": true,
"tornTailGraceMs": 300000,
"keepSnapshots": 10,
"exclude": ["some-bundle-i-trust"]
}
Auto-disable safety policy
Smoke runs in a mock environment: a failure may be a real bug or an environment gap (the plugin needs real DSH services). Therefore:
- A smoke failure alone never auto-disables (only reported +
fixNeeded);
- the previous boot actually crashed (crash marker present) → failing plugins are auto-disabled;
- a plugin explicitly declares
"dsh": { "smoke": true } → auto-disabled on smoke failure;
- a plugin declares
"dsh": { "smoke": false } or is in exclude → smoke skipped;
- broken client artifacts (parse-class checks) → auto-disabled as before.
Wrongly disabled? Remove the matching - id: "xxx" / disabled: true entry from the profile's cordis.patch.yml (the original patch is backed up in repair-backups/).
Data locations
~/.dsh/
├── dsh-preflight.log # run log (rotated past threshold to .old)
├── dsh-preflight-state.json # scan state + smoke fingerprint cache
├── dsh-preflight-report.json # machine-readable summary of every run
├── dsh-crash-state.json # crash marker (written by launcher/desktop, consumed by guard)
├── dsh-boot-state.json # boot marker (written by host plugin, cleared on clean shutdown; abnormal exit = crash evidence)
├── dsh-preflight-block.json # strict-mode block marker (read by launcher)
├── dsh-startup-guard.json # config (optional)
├── repair-backups/ # original files before repair/disable
└── plugin-snapshots/ # manifests + link sources + fingerprints
Integration
Three entry points, so every crash scenario has a fallback — and a bare dsh web with no shell still gets crash quarantine via the host plugin's boot marker:
- Desktop client (dsh-desktop-app): runs
guard-runner.mjs as a child process before spawning the server; writes a crash marker on server crash, clears the boot marker on clean quit
- Web launcher (dsh-launcher.ps1): calls
guard-sessions.mjs in the boot loop; writes a crash marker on crash; refuses to start if a strict block marker exists; clears the boot marker on normal stop
- Host plugin: runs asynchronously early in the dsh web boot; writes/clears the boot marker and triggers quarantine from it
CLI:
node guard-sessions.mjs # fix mode
node guard-sessions.mjs --dry-run # report only, change nothing
node guard-sessions.mjs --mode report # same as dry-run
node guard-sessions.mjs --mode strict # fix + strict block
Core API:
import { runGuard } from 'dsh-startup-guard/lib/guard-core.mjs';
const r = await runGuard(home, { dryRun: true });
// r: { repaired, rolledBack, autoDisabled, broken, hostBroken,
// smokeUnresolved, issues, fixNeeded, blocked, crash, lines, ... }
Development
dsh-startup-guard/
├── lib/
│ ├── index.js # host entry (fire-and-forget, dynamic import)
│ └── guard-core.mjs # core: runGuard + all checks
├── test/guard-core.test.mjs # 73 tests (node:test, mock home, zero deps)
├── cordis.patch.yml # bundle registration
└── package.json
npm run check # node --check lib/*
npm test # node --test (73 tests)
npm run pack:check # npm pack --dry-run
node guard-sessions.mjs --dry-run # safe dry-run against a real home
Design principles:
- fire-and-forget: guard failures are logged, never thrown into the boot sequence;
- atomic writes: every file modification goes through tmp+rename;
- graceful degradation: if the session decoder is missing, only session scanning is skipped;
- single-instance lock:
dsh-preflight.lock serializes the multiple entry points.
License
MIT
Independent community plugin for DeepSeek Harness. Not affiliated with DeepSeek.