Skip to content
dsh-market Browse plugins GitHub 中文

aokamoaki/dsh-startup-guard

Boot-time guard that repairs corrupt session logs, preflights plugin composition, vm-checks client artifacts, smoke-tests host apply() and quarantines crash-causing bundles, so a broken plugin can never brick startup.

Stars ★ 1 Category Development & Runtime Listed 2026-08-16 npm dsh-startup-guard

Install

Inside DeepSeek Harness, with dsh-market

dsh plugin --profile web add dshmarket

Or from the command line

dsh plugin --profile web add dsh-startup-guard

Installing runs third-party code with your own permissions — it can read your files, use your credentials and reach the network. Review the source first, and pin a commit (github:owner/repo#sha) when you can.

README

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.

Check


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

# Check Behavior
1 Session log repair Fixes session.jsonl[.zstd] seq corruption (drop duplicate row or truncate to the last committed row); frame-level detection and truncation of permanent zstd torn tails; prunes stale cache entries for deleted sessions. Originals are backed up to repair-backups/
2 Manifest snapshot + fingerprints Snapshots each profile's package.json / cordis.patch.yml / pnpm manifests plus link: plugin sources into plugin-snapshots/, recording per-bundle host/client/patch content fingerprints (keeps the latest N)
3 Bundle preflight + rollback Verifies third-party bundle dirs resolve; rolls back to the newest fully-resolvable snapshot when missing (24h grace against rollback loops); broken manifests kept as package.json.broken
4 Composition preflight + repair Detects duplicate entry ids, unresolvable name: rows, and fatal YAML shapes; rows whose name: no longer resolves are auto-disabled (with backup); fatal shapes write a block marker in strict mode that the launcher refuses to boot past
5 Client bundle validity Verifies exports["./client"] exists, registers via __ModuleLoader__.load, and actually executes at load time in a vm sandbox; detects duplicate client ids across bundles; broken artifacts are auto-disabled
6 Host apply() smoke Runs every third-party plugin's apply() in a throwaway child process against a mock Cordis context, catching "crashes at startup" runtime errors (e.g. ReferenceError); results cached by content fingerprint
7 Crash quarantine The launcher / desktop app writes a crash marker on an observed crash, and the host plugin also maintains its own boot marker (dsh-boot-state.json: written at apply, cleared on clean shutdown, left behind by abnormal exits). Either piece of evidence forces a full smoke sweep on the next boot and auto-disables failing plugins — closing the "crash → auto-disable → boot recovers" loop. Works for a bare dsh web with no launcher/shell too

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 Behavior
report Detect and report only; never modifies anything
fix (default) Auto-repair / auto-disable / auto-rollback
strict fix + fatal composition shapes write a block marker; the launcher refuses to start and shows a dialog
{
  "mode": "fix",
  "smoke": true,
  "smokeTimeoutMs": 15000,
  "clientVmCheck": true,
  "clientFactorySmoke": false,
  "quarantineOnCrash": true,
  "autoRepairComposition": true,
  "tornTailGraceMs": 300000,
  "keepSnapshots": 10,
  "exclude": ["some-bundle-i-trust"]
}
Option Default Description
mode fix report / fix / strict
smoke true Run the host apply() smoke
smokeTimeoutMs 15000 Per-bundle child timeout
clientVmCheck true Execute client artifacts in a vm at load time
clientFactorySmoke false Also invoke the client factory (stub require)
quarantineOnCrash true Crash marker forces a full smoke sweep
autoRepairComposition true Auto-disable patch rows whose name: no longer resolves
tornTailGraceMs 300000 "Permanent torn tail" write-idle threshold
keepSnapshots 10 Number of snapshots kept
exclude [] Bundles the guard never touches

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:

  1. 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
  2. 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
  3. 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.

Content from the project README on GitHub ↗