DeepSeek Harness Plugin

zhu1090093659/dsh-web#packages/dsh-task-board

Stars ★ 8275 Downloads (30d) 172,440 Category UI Enhancements Added 2026-09-24 npm @linxin666/dsh-client-ui-task-board

Task board for the dsh web GUI: a sidebar multi-column kanban whose cards run in real DSH agent sessions and can also be scheduled with cron expressions, executed host-side even with the browser closed.

Install

# from npm (prebuilt)

dsh plugin --profile web add @linxin666/dsh-client-ui-task-board

# from GitHub (first run asks for allowBuilds approval — follow the hint, retry)

dsh plugin --profile web add github:zhu1090093659/dsh-web#path:/packages/dsh-task-board

Any plugin you install runs third-party code with your own permissions — it can read your files, use your credentials, and reach the network, and tool approvals don’t sandbox it. GitHub-sourced plugins also run build scripts at install time — pnpm blocks those until you allow them, so an install can stop with ERR_PNPM_GIT_DEP_PREPARE_NOT_ALLOWED or ERR_PNPM_IGNORED_BUILDS; dsh prints the exact key to add under allowBuilds in your profile’s pnpm-workspace.yaml, and the install works on the next run. Allowing a build is a trust decision: only install sources you trust, and pin a commit (github:owner/repo#sha).

README

English | 中文

A hot-pluggable DeepSeek Harness (DSH) Web GUI and official desktop client task automation plugin with a Host-authoritative task ledger, real DSH agent session execution, cron background scheduling, cross-platform idle-sleep protection, multi-agent cascades, and automated verification quality gates. It executes unattended background workflows including automated code reviews, routine health checks, and scheduled pipelines without requiring an open browser window. It mounts cleanly via cordis.patch.yml and profiles without modifying DSH core code.

  • The browser is an asynchronous view; closing the page does not stop Host scheduling or execution settlement.
  • Every run applies the pinned workspace, agent preset, and permission before sending the task prompt; by default each run creates its own DSH session, and a task can opt into continuing in its previous session instead (issue #1419).
  • dsh's built-in /goal is armed for every run by default, so the session keeps working automatic continuation rounds until the goal completes and the board settles the execution on that goal's end; each task can turn the option off.
  • The display may turn off while optional power protection keeps the computer from entering idle system sleep.

Features

  • Task board UI: the board is the shell's own center-column panel — like the desktop application's Plugins page, it contributes a row to the shell's official sidebar panel list and a page to the layout's center-column seat, so row geometry, the active highlight, the collapsed rail, the label, and language switching are the shell's to own; the board provides five kanban columns, search, task details, archive/restore, execution history, and links to execution transcripts. Every column is reachable by hand, by dragging a card or from the detail view's status row: the move writes the column and no execution record, so Done or Failed declares work that finished (or failed) outside a tracked run and Running parks work that is under way without a session, while a card the runner is actually executing refuses every move until it settles. Archived tasks are read-only except for restore, delete, and transcript viewing, and cannot run manually or on schedule until restored.

  • Continuation cards (data plane): a new task may paste a <<<FREEZE ... >>>FREEZE block from a session; it parses into a goal/progress/next snapshot persisted with the task (ledger v3). Cards carry a frozen badge, the detail view shows the full snapshot and freeze time, search covers snapshot text, and archive/restore matches plain tasks. The snapshot reuses the freeze security gate at the protocol layer: sensitive patterns become [REDACTED] with a marker, slash-prefixed command lines reject the whole snapshot, and each field is capped at 8 KiB.

  • Handover bundles and the permission confirmation gate: a continuation card may attach a handover bundle — the pinned execution triplet (workspace / agent preset / permission) plus doc/script references. The bundle's triplet overrides the plain pin fields at execution, and the references ride the prompt as a handover preamble. A binding whose effective permission is above the deployment's permission baseline — the Host's own default permission preset unless the profile pins sessionDefaultPermission — is unconfirmed: manual run refuses, cron skips the card and rolls to the next occurrence, and the confirm button in the task detail resolves the binding; any later permission or bundle change re-arms the gate.

  • Claim provenance wrap and source audit: executing a continuation card (a card with a frozen snapshot) mandatorily wraps the task instruction in a source-declaration template — freeze instant, source session, and an unreviewed-content warning — composed after the handover preamble so the picking-up agent stays wary of stored prompt injection in card text. The session issuing a create/update action is stamped into the snapshot (frozenBy, re-stamped when the snapshot is replaced), and the session issuing a run/rerun lands on the execution record (initiatedBy) together with a captured copy of the freeze provenance; both are visible in the task detail. The initiator is client-asserted audit metadata, not a trust boundary.

  • Task tags (issue #1521): a task may carry up to eight labels. A label renders as a colour-toned badge on the card — the tone is hashed from the name, so one label always paints the same way and no colour is stored — the board header gains a multi-select tag filter built from every label in use (including archived tasks), and search also matches label names. A label with an "execution hint" is injected ahead of the execution prompt on every run as a 标签提示 block; a label without one is display and filter only, so an untagged task's prompt is byte-for-byte what it was before the feature. Labels stay editable after the first run: they classify the task and shape the next run, they are not the record of what already ran. A Manage labels action on the filter row opens the label manager: every label in use with the number of tasks carrying it, a rename that rewrites the label on every card (merging into an existing label of that name and keeping that label's execution hint), and a delete that removes it from every task including archived ones. Both are ledger-wide Host transactions, so several windows looking at one board stay consistent.

  • Subtasks and cascade runs: a task can be given subtasks, either by creating one from its detail view (the form starts from the parent's workspace, preset, permission, and model, and each stays overridable) or by linking an existing task that has no parent yet; a subtask can be detached again once it is not running. The lineage gate lives in the Host: the parent must exist and be on board, a task can never be attached under one of its own descendants, and a tree may not exceed the configured maxSubtaskDepth (1 by default, 3 maximum). Running a task also runs its whole subtask tree concurrently — one DSH session per member, all under one run group — and the parent card stays in the running column until its own turn and every subtask have settled; its verdict fails if any member failed, and one failing subtask never stops the others. The board marks parent and subtask cards, the detail view lists the direct subtasks, and the header offers a one-click hide-subtasks filter.

  • Agent Team runs (opt-in per task): a task may opt into team execution in its detail view (or through task_board_create/task_board_update). Running such a task starts ONE session — the Team Lead — and the Host then asks the Agent Teams service to spawn one teammate per subtask inside it, attaching each teammate's session to that subtask's execution. The subtree is flattened into that one Team (only a Lead may spawn); the Lead's prompt lists every teammate by name and points at the team tools, and the Lead's verdict governs the run: a teammate's own completed turn settles its card even while the Team keeps that session alive, and once the Lead's own outcome lands, every member still open is settled with it. A plain cascade prompts the same way but names the independent sessions instead. The mode needs the optional agentTeams service: a deployment without it refuses the run by name instead of silently degrading, and a subtask pin the Lead session does not already carry is refused, because a teammate inherits that session's permission and cannot be narrowed below it — a pin the Lead already covers runs the member at the Lead's authority instead of failing the run. Team runs always mint a fresh Lead session (teammate names are immutable within a Team) and use teamProvider. An execution whose session history cannot be read at all is reported failed with the reason after two minutes of polling, so an unreadable session can never leave a card in the running column.

  • Project partition (issue #1536): the board header offers a project row built from the deployment's DSH workspaces — "all projects" plus one entry per registered project. Selecting a project narrows the columns to the tasks pinned to it, and tasks with no pinned workspace stay visible under "all projects". Opening the new-task form while a project is open preselects that project as the task's workspace, and "new project…" registers a host directory through the same runtime call the GUI's own add-project uses. A root task created without a project choice — from the form or through the board's agent tool — inherits the workspace of the session that created it, and a card that still pins nothing runs in the deployment's most recently used workspace instead of the Host's own working directory.

  • AI parse of pasted text (issue #1540): the new-task form takes text copied from anywhere and has a model turn it into the title, description, and run prompt. The model is one of the deployment's configured models (the same list the task's model pin uses, first entry preselected), and the call runs on the Host behind the board's usual loopback and same-origin fence, with a 45 s budget and a cancel affordance. The draft only fills the form: nothing is created until the task is submitted, and a failed parse leaves what you already typed untouched.

  • Collapsible task form: the create/duplicate/subtask dialog groups its configuration into collapsible regions — task content open by default, then labels, execution settings, run mode, handover, and scheduled runs — and every collapsed region keeps a one-line summary of the values it holds, so the dialog fits without a scrollbar (its body keeps an overflow fallback for very short windows). The agent-preset field is named "Agent preset" and lists the deployment's built-in presets under localized names plus any user preset, with an inherit default that names the preset a run without a pin actually uses.

  • Host-authoritative ledger: tasks, schedules, and execution records live in $DSH_HOME/task-board/ledger-v2.json; browser actions become confirmed Host transactions.

  • Bounded execution history: each task keeps the most recent 20 execution records; the oldest runs are trimmed when a new run starts, so ledger size and write cost stay bounded regardless of how often a task has run.

  • Real execution: manual and scheduled runs use the same Host runner, which by default creates a fresh session, renames it, applies the agent preset and /permission <id>, then queues the task prompt.

  • Goal-driven runs (on by default): unless a card opts out through its detail-view checkbox (the new-task dialog starts checked), the runner queues the task prompt and then arms dsh's built-in /goal with that same composed prompt as the objective. dsh's goal-round driver keeps starting continuation rounds in the session until the agent marks the goal complete, and the board keeps the execution in running until the goal leaves its active phase: a completed goal settles the run as succeeded, a blocked one fails it with the goal's own reason. The option is per task (goalRun, absent means on) and is available to task_board_create/task_board_update too.

  • Goal acceptance (on by default): a task executed in goal form must pass ONE acceptance before update_goal(action: complete) may take effect, because the board gates that call on the official tool pre-execute lifecycle instead of trusting the agent's own report. Acceptance runs the default final acceptance of the installed dsh-llm-verifier (MIT): the three coding criteria (Specification Adherence, Output Match, Error Signal Detection), a 0.65 threshold applied to the total AND to every criterion, two judge rounds per criterion with the A/B slots swapped and averaged, the task's real trajectory (tool calls, their output, assistant prose) judged against the empty-work baseline, the work must beat that baseline, and — when the deployment records workspace changes — the HOST's own record of what the run changed on disk (file list with added/deleted counts and bounded per-file comparisons) is attached as the prompt's reference context so a described-but-unapplied patch cannot pass. One execution may accept twice: the first failure returns the total, the per-criterion scores and the located findings to the fixing agent, the second failure ends that execution as failed. The budget lives on the execution record, so a repeated completion call, a new goal round, a plugin reload and a Host restart all reuse the same cycle, while a rerun or a scheduled occurrence is a new execution with its own budget. An anomaly (timeout, authentication failure, unparseable judge answer, unresolvable judge route) is recorded separately from a quality verdict, never consumes the quality budget, and is bounded so it can neither loop nor pass silently. The running column shows executing / verifying / fixing, and each execution's row carries its verdict, judge model and level, count, scores with thresholds, findings, evidence scope and token usage. Forced acceptance also keeps the old fallback paths honest: a paused goal, an unreadable projection, a completed turn and a manual settle can no longer settle a goal execution as succeeded without a matching pass record.

  • Optional session reuse: a task can opt into continuing in its previous execution's session (issue #1419). Reuse happens only when that session is idle and still present in the runtime roster — the Host then re-applies the pinned permission and model on it and queues the prompt, keeping the conversation title and history; otherwise the run mints a fresh session as before, so an unknown roster or a busy session never blocks a scheduled run.

  • Fail-closed pins: a missing workspace, missing or broken preset, or rejected permission command fails before the task prompt is sent.

  • Host scheduler: 5-field cron supports *, */n, ranges, comma lists, and Sunday 0/7. Each rule carries its own IANA time zone (the Host's zone by default), and day-of-month/day-of-week follow Vixie semantics: both fields restricted means OR, any other combination means AND. Wall-clock gaps at a daylight-saving transition are skipped, and an ambiguous repeated time fires once, at the earlier instant.

  • Deterministic recovery: a running execution with a recorded session is observed after restart; an interrupted start without a session id is cancelled and is not resent.

  • Live synchronization: mutations return a full revisioned snapshot; SSE announces revision, scheduler, and power changes, while reconnect and page visibility recovery fetch a full snapshot.

  • Optional idle-sleep protection: off by default; when enabled it covers every running DSH session, enabled non-archived task-board schedules, and unknown session state.

  • System-prompt injection: the Host registers a plugin:task-board section (order 200) through SystemPrompt.section, and the task-board settings can disable the announcement without disabling the board. The guidance also reminds agents to close any visible todo_write plan before the final answer.

  • Agent tools: every session gets eight model-facing tools (task_board_list, task_board_get, task_board_create, task_board_update, task_board_set_parent, task_board_run, task_board_manage, task_board_schedule) that drive the same Host ledger the browser drives, so an agent can list the board, create subtasks, link or detach them, run a cascade, move a card to any column (declaring it done, failed, or in progress without a run), archive/restore/delete it, settle a card the board can no longer observe, and arm its cron schedule from the conversation.

  • External provider extensions: the GitHub Issues extension (@linxin666/dsh-client-ui-task-board-github, enabled by default) synchronizes GitHub Issues into board cards. It is a provider of THIS board, so its configuration renders inside this plugin's own settings card — the section only appears while the extension is installed, and its repository/credential form only while the extension is on; see its README.

Architecture and protocol

The board view renders on first open and keeps its local view state when closed and reopened. Host synchronization, scheduling and execution remain active independently of the view.

  • src/index.ts mounts the Host service through the official @deepseek-ai/dsh-api-gateway, @deepseek-ai/dsh-workspace, and @deepseek-ai/dsh-host-webserver SDKs.
  • src/host-ledger.ts serializes actions and persists { schemaVersion: 3, revision, tasks, scheduler, recentRequests } through a temporary file plus atomic rename.
  • src/host-service.ts owns cron firing (a one-shot timer armed at the ledger's nearest target through the host's timer service, falling back to process timers when the host serves none), missed-trigger skipping, runner launch, restart reconciliation, and power reasons.
  • src/client/native-panel.tsx registers the board's sidebar row and center-column page (the official sidebar.panellist list seat and the keyed main seat) and maintains the center-column exclusivity protocol with the ssh panel.
  • src/client/host-api.ts imports legacy browser data once, submits idempotent actions, and treats Host snapshots as the only confirmed UI state.
  • Same-origin endpoints are GET /api/task-board/state, GET /api/task-board/events, and POST /api/task-board/action.
  • Every endpoint requires a browser same-origin marker: sec-fetch-site: same-origin, an Origin header, or the Host's dsh-auth-* browser-auth cookie. The last one is how the DSH Desktop shell reaches the board: it serves the Web GUI from dsh-app://app/ and forwards that page's requests itself, dropping Origin and sec-fetch-site and attaching the authority-bound cookie it redeemed from the Host's launch URL at startup. Direct access is restricted to the DSH loopback origin; an authenticated same-host reverse proxy must use an explicit Host allowlist and a server-injected token. POST requests additionally require JSON. Ordinary actions are limited to 64 KiB and import to 2 MiB. The action union has no command, executable path, shell text, or arbitrary argument field.

Agent tools

The board is operable from a conversation, not only from the GUI. Each tool drives the same Host ledger, so a card created in the GUI is immediately visible to agents and vice versa, and every gate the UI honors still holds. The surface follows the enabled switch: a disabled board answers no tool call, and a deployment whose runtime serves no tool registry still mounts the board with the GUI intact.

  • task_board_list lists cards with filters (column, parent, roots only, label, free-text query, archived) plus the board summary: revision, time zone, subtask depth limit, session-default permission, and column counts.
  • task_board_get reads one card in full: prompt, labels, parent link, direct subtasks, execution targets, schedule, permission-gate state, and the last ten execution attempts with their session ids, initiator, and outcome.
  • task_board_create creates a task or, with parentId, a subtask; execution targets left unset inherit the parent, and the deployment subtask-depth limit applies.
  • task_board_update edits content, labels, and execution targets; an empty string clears a target and an empty label array clears the labels.
  • task_board_set_parent links an existing card under a parent, or detaches it with an empty parent id.
  • task_board_run runs a card now (optionally re-running a settled one), cascading over its whole subtask tree; it consumes real API quota and refuses an unconfirmed above-default permission with confirmation-required.
  • task_board_manage moves a card to any column — the move writes the column and never an execution record, so backlog/todo plan, done/failed declare work that finished outside a tracked run and running parks work that is under way without a session, while a card with an open execution refuses the move until it settles — archives or restores it, deletes it, or settles a running card the board can no longer observe (recording a cancelled verdict with the caller as the reason and returning the card to todo), with the Host's running-task and subtask guards.
  • task_board_schedule arms, changes, or disarms a card's cron schedule, including its IANA time zone (an empty timeZone clears it back to the Host zone).

There is deliberately no tool that confirms a permission binding: that gate exists so a human lifts an above-default permission, and an agent able to stamp it would make the gate decorative. An agent that hits confirmation-required asks the user to confirm the card in the board UI. Tool calls are attributed: a run records the calling session as its initiator, and a create/update stamps it into a continuation card's snapshot.

Install

Install the aggregate package or this package alone, then restart dsh web:

dsh plugin --profile web add @linxin666/dsh-client-ui-task-board@latest

For local development:

git clone https://github.com/zhu1090093659/dsh-web.git
cd dsh-web
pnpm install
pnpm build
dsh plugin --profile web add link:$(pwd)/packages/dsh-task-board

Configuration

This plugin's settings card groups its options into collapsible sections — the board and its runtime behavior, task acceptance, and the section a provider extension contributes (the GitHub Issues integration). Every section starts collapsed, and one save writes them all.

Key Default Behavior
enabled true Enables the Host service and browser board.
announceToAgent false Opt-in: when true, adds the task-board guidance section to agent system prompts.
preventIdleSleep false Holds one system idle-sleep assertion while any DSH session runs, any schedule is enabled, or session state is unknown.
trustedProxyHosts [] Canonical host[:port] authorities accepted only through the authenticated loopback reverse-proxy path.
proxyTokenEnv DSH_TASK_BOARD_PROXY_TOKEN Environment variable containing the reverse-proxy token; the token itself is never stored in plugin config.
sessionDefaultPermission follow the Host Explicit baseline for the permission confirmation gate. Unset, the board follows the Host's own default permission preset (what new DSH sessions start at) and falls back to read-only when the deployment serves no permission catalog. A card whose effective permission (handover bundle or pin) is above the baseline requires a human confirmation before it may run; cron refuses unconfirmed cards.
maxSubtaskDepth 1 Subtask depth limit, 1 to 3. At 1 a task may carry one level of subtasks and a subtask cannot be given subtasks of its own; every extra level multiplies the sessions one run of the root opens.
goalVerification true Goal acceptance for executions this board starts. When on, update_goal(action: complete) inside a task execution is refused until an acceptance pass is recorded for that execution. Only goal-form executions are affected: plain chat and a task pinned to goalRun: false are untouched.
goalVerificationModel '' (inherit) Judge model route as provider/model. Blank inherits the HOST model catalog default — never the card's pinned execution model.
goalVerificationReasoningEffort '' (inherit) Judge reasoning level. Blank inherits the host default level; a level the resolved model does not declare is never sent, and the fallback to that model's own default is recorded and shown.
teamProvider spawn Continuable-subagent provider the Agent Teams service composes a teammate from. Only team-mode runs use it; it matches the Agent Teams tool plugin's freshProvider default.

Direct browser access remains limited to the DSH loopback origin. For a same-host authenticated reverse proxy, bind DSH Web to loopback, set trustedProxyHosts, place a high-entropy token in the environment variable selected by proxyTokenEnv, and configure the proxy to replace (not forward from the client) X-Dsh-Task-Board-Proxy-Token after it authenticates the request. The proxy Host must be allowlisted, and the browser Origin must have that same authority. Restart the Host after changing these composition-level proxy settings.

On macOS the backend starts /usr/bin/caffeinate -i -w <host-pid> and never requests -d. On Windows it starts the absolute Windows PowerShell under SystemRoot with a fixed helper that requests only ES_CONTINUOUS | ES_SYSTEM_REQUIRED; it never requests ES_DISPLAY_REQUIRED, changes a power plan, or requires administrator privileges. On Linux it starts a systemd-logind idle block inhibitor only from /usr/bin/systemd-inhibit or /bin/systemd-inhibit; it does not request sleep, handle-lid-switch, or a display/screensaver inhibitor. A Linux host without systemd-logind reports unsupported or a visible error and does not start a desktop-specific fallback. Other platforms report unsupported.

Data storage and migration

  • The authoritative ledger file is $DSH_HOME/task-board/ledger-v2.json (the file name is historical); the current document schema is v5, and an older document (v2, v3 or v4) is migrated losslessly in place on the next Host start. New POSIX files use mode 0600; Windows inherits the user directory ACL.
  • v5 adds the per-execution acceptance block (verification). The migration deliberately does NOT stamp one, so an execution opened before v5 keeps settling on its historical verdict and no in-flight run is retroactively judged by a gate that was never armed for it. A malformed block is dropped (that execution is then treated as unverified — fail closed), and an imported execution record never carries one, because a fabricated pass record must not let imported work look accepted.
  • A v2 to v3 migration failure (structurally invalid task rows) fails closed with an explicit error and keeps the original file untouched; it never restarts from an empty ledger silently. A corrupt or unsupported-schema file is moved to a collision-resistant ledger-v2.json.corrupt-* name and the Host starts with an empty ledger plus a visible scheduler error. The corrupt bytes are not overwritten.
  • On the first upgraded page load for an origin, dsh.taskBoard.v1 is imported by stable source and request ids. Tasks merge by id, strictly newer browser top-level fields win, equal timestamps keep Host fields, and execution records merge by execution id.
  • The most recent 256 request ids and SHA-256 action fingerprints are stored with the ledger, so a retried mutation remains idempotent after a Host restart without duplicating full action payloads.
  • Task labels are an optional tags field on the task row ({ name, promptPrefix? }[]) and needed no schema bump: a v3 document without it loads unchanged, and a malformed list is repaired entry by entry (blanks, repeats, and over-long names dropped, count capped) rather than dropping the task row.
  • The goal opt-in is an optional goalRun field on the task row and needed no schema bump either: absent means on, an explicit false is the opt-out, and a stray true is repaired back to absent on load.
  • The import marker dsh.taskBoard.v2.hostImported stores the confirmed Host ledger generation only after import succeeds. A new or recovered ledger generation is offered the retained v1 data again. The v1 localStorage value remains untouched as a read-only rollback copy.
  • One Host process owns a task-board ledger directory at a time through $DSH_HOME/task-board/ledger-v2.lock; a second Host using the same DSH home fails closed instead of concurrently writing the ledger.

Security model

  • The plugin stays inside the existing DSH Web deployment and network boundary and emits no permissive CORS headers. State, action, and SSE routes share the same access fence; bare local command-line requests are not accepted as browser requests.
  • All mutation payloads use a strict, versioned discriminated union; schedule-owned timestamps and execution outcomes cannot be written by the browser.
  • Workspace, preset, permission, cron, task status, and imported records are validated again on the Host.
  • A card's effective permission above the configured session default enters a pending-confirmation state: the Host refuses manual runs and cron triggers until a human confirms the exact binding, and changing the pinned permission or the handover bundle clears the confirmation (no confirm-then-swap escalation).
  • A task prompt is data sent to a DSH agent session. The protocol does not accept shell commands, PowerShell bodies, executable paths, or configurable helper arguments.
  • Task labels are client-asserted like the prompt itself and ride the same gated action channel: the protocol gate rejects a blank name, an unknown key, more than eight labels, and an over-long name or hint. A label's injected hint is delimiter-escaped (it cannot forge the continuation-card provenance markers) and is placed outside that provenance wrap.
  • The subtask lineage is validated on the Host, not in the browser: the parent must exist and be on board, attaching a task under one of its own descendants is refused, and the resulting depth must stay within maxSubtaskDepth. A subtask that leaves its own permission unset resolves the parent's binding at launch together with the parent's human confirmation — the binding is never copied onto the card, so detaching a subtask cannot leave a confirmed elevated task behind — while pinning its own permission puts it back under the confirmation gate; a run whose subtask tree contains an unconfirmed binding is refused before any session starts, and cron rolls the schedule instead.
  • The agent tool surface reaches the same Host ledger through the in-process service rather than the HTTP fence, and it carries no confirmation capability: refusals, fail-closed pins, the depth gate and the running-task locks all still apply, and no tool call can lift an above-default permission binding.
  • Power helpers use fixed executable paths, fixed arguments, shell: false, and bounded retry delays of 1, 2, 5, 10, then 30 seconds. The Linux helper follows the Host stdin lifetime so the systemd inhibitor is released automatically after an abnormal Host exit.

Build and test

Node 20 or newer and the official NPM SDK packages are required; no DSH source checkout is used.

pnpm --filter @linxin666/dsh-client-ui-task-board typecheck
pnpm --filter @linxin666/dsh-client-ui-task-board test
pnpm --filter @linxin666/dsh-client-ui-task-board build

Set DSH_POWER_SMOKE=1 to opt into the native helper smoke test on Windows, macOS, or Linux. It starts the fixed helper, waits for readiness, releases it in cleanup, and confirms process exit without changing the system power plan. Linux first probes systemd-logind with a bounded timeout; without a usable system bus the native portion is skipped while pure logic tests remain available.

Manual verification

  1. Mount the package, restart dsh web, open the task board, and confirm the Host time zone and power status are visible.
  2. Create and edit a task; refresh or open a second same-origin tab and confirm both show the same Host revision.
  3. Run a task with pinned workspace, preset, and permission; confirm a new session appears and the task settles from its turn/end history.
  4. Run a task with the /goal option checked: confirm the session starts a goal and the card stays in running across continuation rounds until the goal completes, then settles as succeeded. Uncheck the option and confirm the next run is a single turn that settles from one turn/end.
  5. Enable a near-future cron, close all browser pages, and confirm the Host still creates and settles exactly one execution.
  6. Stop the Host past a cron occurrence, restart it, and confirm the missed occurrence is skipped and nextRunAt rolls forward from current Host time.
  7. Enable preventIdleSleep, run a long session, and let the display turn off; after restoring the display, confirm the session continued and the execution settled.
  8. Disable the setting and all schedules, stop DSH, and confirm the helper exits; on macOS, pmset -g assertions should show no display-sleep assertion from this plugin.
  9. On Linux, use systemd-inhibit --list to confirm that only an idle/block entry exists; the display should still follow desktop settings, while manual sleep and lid close remain under system policy.

Known limitations

  • Missed occurrences during Host downtime, system sleep, or a long pause are skipped and never queued for catch-up.

  • A task that is already running skips its due occurrence and rolls to the next cron match; task runs never overlap or queue.

  • DST follows the Host local wall clock: a nonexistent spring-forward minute is skipped, and a repeated fall-back minute is not replayed a second time.

  • Power protection prevents only idle system sleep. It deliberately allows display sleep and lock.

  • Lid close, manual sleep, hibernation, shutdown, low-battery forced sleep, and enterprise power policy are outside the guarantee.

  • The plugin does not schedule wake timers and cannot wake a computer that is already asleep.

  • Linux requires systemd-logind and policy permission for the current user to acquire an idle block lock. Containers, WSL, hosts without a system bus, and non-systemd systems may report unsupported or error. Whether a desktop also associates a logind idle lock with display idleness is desktop policy; the plugin does not request a screensaver or display inhibitor.

  • Keeping enabled schedules armed may increase battery consumption because protection starts before their future trigger time.

  • Host execution consumes the same API quota as an ordinary DSH agent session.

  • Running a task also runs its subtask tree: one DSH session per member starts at once, so a deep tree opens several concurrent sessions and each consumes API quota.

  • Agent tool calls are model-driven: a run or a scheduled cascade started from a conversation consumes the same API quota, and an agent can arm a schedule that keeps firing until it is disarmed or the board is switched off.

  • A goal run keeps working for as many rounds as the objective needs: every round consumes API quota, and the session stays busy until the goal completes or dsh blocks it (round limit, a rejected round, or a failed queue), which the board reports as a failed execution.

  • Goal mode needs the runtime's /goal command and a command dispatcher. A deployment that serves neither still runs every card as a single turn; the host log reports that the goal was unavailable instead of failing the run.

  • Acceptance spends model requests: one acceptance is three criteria times two rounds (six judge requests), and one execution may accept twice, so a goal cycle that needs its one repair costs up to twelve extra requests on top of the work itself.

  • No cost estimate is shown for an acceptance: this deployment exposes no reliable per-token price for the resolved judge route, so the report lists tokens only.

  • The host-observed workspace-change block appears only when the deployment records changes and the read succeeds; an unavailable service or a failed comparison degrades the evidence to the trajectory alone rather than failing the acceptance.

  • Acceptance is enforced only where it can be: a run that never became a goal run (/goal refused or unavailable) and a teammate execution are not gated, and their record says so explicitly instead of implying they were verified. A deployment that serves no model catalog cannot resolve a judge route, so a completion claim fails closed and is recorded as an acceptance anomaly.

  • The first version always judges with the coding criteria: there is no automatic rubric selection, so a non-coding task is judged by engineering criteria (the settings copy states this).

  • If a third-party verifier (for example the installed dsh-llm-verifier) also enables its own automatic acceptance, both judges score the same session independently: this board's acceptance gates completion while the other only steers, and no public SDK interface lets them share one verdict. Turning that plugin's automatic mode off is the only reliable way to avoid paying for two judgments.

Telemetry

The browser half sends one anonymous install heartbeat per UTC day to dsh-market.com: a random localStorage id plus this package's name, nothing else. The server stores only a salted hash of that id, never IP addresses, and exposes aggregate counts only. See docs/telemetry.md for the full contract.

Content from the project README on GitHub ↗

Links

More in this category

View the whole category →

Community comments

Comments are public GitHub Discussions. Loading them connects to GitHub and Giscus; a GitHub account is required to post.