npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

dsh-taskloop

v0.1.0-alpha.10

Published

Taskloop task workspace for DSH: list, board, task detail, context, and execution timeline

Readme

dsh-taskloop

Taskloop is an Agent-facing todo workspace for DSH. People publish Tasks and follow execution progress; Agents move the work forward. It uses a restrained task-list UI inspired by TickTick and provides:

  • one all-tasks list, projects, and task creation;
  • a separate trash view with task restore;
  • one level of full Task children under a parent goal, with creation, association, and persistent order;
  • read-only checklist and related-document views parsed from the task body;
  • configurable board statuses; a state with task references, including trash, cannot be deleted;
  • live unfinished top-level goal counts, a refresh action, and floating task details when list space is limited;
  • task details with separate execution status, progress, tags, and related documents;
  • a collaboration trace with action headings; title and status changes show their new value;
  • a three-column desktop layout with the project sidebar, task list, and task editor; task title and body changes auto-save;
  • SQLite persistence for tasks, projects, task events, contexts, and tool calls;
  • revision checks for task writes, transactional writes with their audit records, and idempotent Agent progress submissions;
  • a right-Sidebar entry plus a full-browser page at /taskloop.

Opening a task shows its title as text. Click the title to edit it. Enter during IME composition confirms the input; ordinary Enter saves the title. Add, edit, check, or remove checklist items and related documents in the task body. New task bodies start empty. Task selection adds ?taskid=<id> to the current URL; reloading that URL opens the same task. Project and tag order is stored in SQLite. Drag the handle to reorder; Space and arrow keys provide keyboard controls.

Auto-save submits only changed title/body fields. Clean fields follow newly read server values; conflicting local input is preserved. Leaving a task waits for pending writes, including edits or reversions made during a save. If a write fails, retry it or explicitly discard the local title/body through 重新加载. Deleting a project or tag refreshes task revisions, including trash, before later edits or restores. Search covers the complete plain-text body, including content after the short list description, without matching HTML attributes.

Use ## 检查项 with one - [ ] item or - [x] item per line. Use ## 相关文档 with [type][name][URL, group number, or protocol address][desc] per line. The parser also accepts Markdown links and standalone URLs. The visible text of each document, including brackets and address, is limited to 150 Unicode characters. HTTP and supported app protocol addresses render as links; group numbers remain text. The sidebar lists are read-only views. Edit every checklist and document in the task body; SQLite stores derived projections and document history.

Parent goals and subtasks

A top-level Task can have one level of children. Each child is a full Task with its own body, status, priority, dates, tags, checklist, progress, related documents, tool calls, and history. parentId identifies its parent; sortOrder preserves child order. Self-parenting, cycles, and grandchildren are rejected.

In parent details, press Enter to create a child and use pointer or keyboard controls to reorder children. Task menus can add a child, associate an existing Task through a searchable parent picker, change its parent, or detach it. Child details can return to the parent; each child's task URL still opens directly.

Children appear as nested second-level nodes under their parent in the main list, expanded by default, with indentation and connector lines. Manually collapse or expand each parent group. Search and filters retain parent context for matching children and count matching roots and children separately. Project and sidebar unfinished counts count top-level goals. Children follow the parent's project, including trashed children when the parent changes project.

The completion button completes or reopens a task directly. A parent with active children waits until all are done and a person selects 验收并完成; it does not complete automatically. Agent and system completion is rejected with TASK_PARENT_REVIEW_REQUIRED. Reopen a completed parent before creating, associating, restoring, or reopening an unfinished child.

Deleting a parent moves its active children to trash in the same batch. Restoring it restores only that batch; independently deleted children stay in trash. The trash UI asks the person to restore a deleted parent before restoring its child.

Product direction

Taskloop is designed around a human-controlled workflow: people advance work and inspect the trace, while Agents make changes through explicit interactions. The workspace gathers enterprise information from IM, meeting notes, and documents, then carries that context into task execution. Tool calls are recorded as traceable nodes so a task can link back to the session that produced each action.

When it runs inside DSH, the workspace tabs are rendered in the top bar and the plugin itself remains in the host's right Sidebar. When opened as the full browser page, the workspace keeps its left sidebar and its overview tabs. The Host owns the storage boundary. Tasks are stored in SQLite at:

$DSH_HOME/tita-agent/taskloop/taskloop.sqlite

If DSH_HOME is not set, the default is ~/.dsh/tita-agent/taskloop/taskloop.sqlite. The browser surface uses the same /taskloop/api routes in the embedded and full-page modes, so task creation and human/Agent actions survive a reload.

The host must run on Node.js 22.5 or newer because the plugin uses Node's built-in node:sqlite runtime module. No separate database service is required.

Existing SQLite databases migrate in place by adding parent_id, sort_order, delete_batch_id, and the derived body_text search field. Existing bodies are backfilled transactionally without changing task revisions. Hierarchy writes retain revision checks, transactional audit records, and Agent idempotency.

Task content editing uses Tiptap, an open-source, headless React editor built on ProseMirror. The editor stores the rendered body as content_html while the short description remains available for list search and summaries. Uploaded images are streamed to the local assets directory and the body stores their relative URL; legacy Base64 images remain readable.

The basic API is:

  • GET/POST/PUT /taskloop/api/tasks for reading and creating tasks. POST accepts parentId to create a child. PUT only seeds an empty database; it cannot replace existing work or history. A task can omit its project;
  • GET /taskloop/api/trash and POST /taskloop/api/tasks/:id/restore for soft-deleted tasks;
  • GET/PATCH /taskloop/api/tasks/:id for task details and rich-text edits. GET returns task, an optional parent, and a bounded subtasks summary with total, done, items, and hasMore; items contains at most 25 children. PATCH accepts parentId; an empty string or null detaches the task;
  • PUT /taskloop/api/tasks/:id/subtasks/order with { "ids": [...], "expectedRevision": n } for child order. ids must contain the complete active child set exactly once. A successful reorder updates the parent and child revisions;
  • GET/POST/DELETE /taskloop/api/projects and /taskloop/api/projects/:id for projects;
  • GET/POST /taskloop/api/tags and DELETE /taskloop/api/tags/:id for the managed tag catalog. Deleting a tag removes only that tag from tasks;
  • GET/POST /taskloop/api/statuses and DELETE /taskloop/api/statuses/:id for the workflow catalog. Statuses have a name and todo, inProgress, or done category. At least one state must remain;
  • PUT /taskloop/api/projects/order and /taskloop/api/tags/order with { "ids": [...] } for persistent catalog order;
  • POST /taskloop/api/tasks/:id/actions for status changes, Agent updates, and human Agent requests. In a DSH session, a request is sent to that session's Conversation service and then recorded in the task history;
  • GET/POST /taskloop/api/tasks/:id/documents and PATCH/DELETE /taskloop/api/tasks/:id/documents/:documentId for related documents; edits and deletes require expectedRevision. related documents use { "content": "[type][name][address][desc]" };
  • GET/POST /taskloop/api/tasks/:id/progress for immutable execution progress;
  • GET/POST /taskloop/api/tasks/:id/tool-calls for traceable tool calls;
  • GET /taskloop/api/tasks/:id/events for the task audit trail.

Agent tools

Taskloop registers eight narrow tools through ctx.tools.register. Every tool uses the taskloop_ prefix so it does not collide with tools from other plugins:

  • taskloop_task_list: query task summaries by status id, priority, tag, project, and keyword; parent_id: "<id>" returns that parent's children and parent_id: "" returns top-level tasks. Use cursor for later pages. Returns ordered status, project, and tag catalogs, plus defaultStatus;
  • taskloop_task_get: read one task, its complete checklist, workflow semantics, and a bounded plain-text bodyText. The task body is the source for checklist, related document, and progress content. Use ## 检查项 with - [ ] / - [x] items, ## 相关文档 with [类型][名称][地址][说明], Markdown links, or standalone URLs, and ## 进展 with one ### <时间> · <角色> heading per entry. The same format is rendered back verbatim, so a body read and written back is unchanged. Children include parentId, parentTitle, and sortOrder; parents with active children include a bounded subtasks summary. Rich HTML, complete description, and history are not returned;
  • taskloop_task_activity_list: read the body's progress entries (kind: progress, newest first), related documents (kind: documents), event headings, or tool-call summaries one bounded page at a time. include_deleted: true shows removed document history;
  • taskloop_task_create: create work with a title, plain-text body, existing status id, project, start date, end date, priority, and tags; optional parent_id creates a full child Task;
  • taskloop_task_update: update the task title, body, project, dates, priority, tags, status, or parent_id; an empty parent_id detaches the task. Only supply the fields to change. body_mode: append inserts the new prose in front of the structured sections, so appended text never becomes a checklist item or a progress report;
  • taskloop_status_create: create a unique board state with a name and todo, inProgress, or done category;
  • taskloop_status_delete: delete an unused state. References from active or trashed tasks block deletion, and at least one state must remain;
  • taskloop_task_submit_progress: append one progress entry to the body, headed by the local time and the actor Agent, and keep its DSH session, call, and turn references in the task history. The result carries the updated task, whose revision the next write must use.

Hierarchy uses these existing tools. The child summary contains at most 25 items; read further children through paginated taskloop_task_list calls with parent_id. Agents can complete children, but a person must accept their parent.

Every Agent mutation requires an idempotency_key. Reuse the same key and the same arguments for network retries. Task updates require the revision returned by taskloop_task_get or the latest write result. Stale writes are rejected instead of replacing newer data. Checklist and document changes are task body updates, so use the task revision from the mutation result for the next write. The same SQLite transaction stores the mutation and its replay result. Agent progress uses this Agent-scoped operation record for deduplication, so different Agents may use the same key independently. HTTP progress keys remain task-scoped and reject retries with different summary/body content. Replay results are retained for 30 days. Older keys stay reserved, so a very late retry fails safely instead of applying the mutation a second time.

status is an execution-state id from statuses; statusName and statusCategory explain its meaning. priority is high, normal, or low. tags are only classification labels: a state id or name is rejected as a tag. Execution reports belong in taskloop_task_submit_progress; submitting progress does not change the task state automatically.

task.checklist and the progress and documents activity pages are parsed views of the task body. Change them with taskloop_task_update by replacing the complete body; use taskloop_task_submit_progress to append one progress entry without rewriting the body. Read up to 20,000 characters with taskloop_task_get; if it returns bodyTruncated: true, do not replace the body with incomplete text. The documents activity page keeps a read-only history of changes found in the body, and a document line is at most 150 visible characters. Start/end dates use YYYY-MM-DD; use an empty string to clear a date or project. end_at is the single deadline field; the former due tool argument is removed.

The former checklist and document mutation tools are no longer available. The documents activity kind remains read-only. Unknown or obsolete arguments fail explicitly. Error messages explain how to recover from task revision conflicts, invalid states, oversized document content, and reused idempotency keys. After a revision conflict, read the latest task and issue a new operation with a new key.

When body is included in taskloop_task_update, body_mode is required. Use replace to replace the body, or append to retain existing rich text and append escaped plain text. This avoids accidental loss of formatting and images.

Agent inputs and persisted fields have explicit size limits. Create/update results omit body fields and legacy progress placeholders. The bounded bodyText in taskloop_task_get is the body read path. Progress and tool-call activity pages omit rich HTML and complete tool input/output payloads. Event pages use the same heading rules as the UI: only title and state changes include their new value.

Progress is deliberately not a field accepted by taskloop_task_update. One progress entry is one ## 进展 block in the body, so the panel, the trace, and the Agent read the same text; taskloop_task_submit_progress writes it and emits a progress_submitted event that keeps the Agent's DSH reference. An Agent that replaces the body must therefore read it first, or the entry it just appended is lost. Rows written by the retired progress API stay readable through the progress activity page (source: "projection") and are no longer written.

Build

pnpm --filter dsh-taskloop build
pnpm --filter dsh-taskloop test