From 5d1359347650c30f41a6aafa5313e473cb377185 Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 00:45:37 +0000 Subject: [PATCH 1/2] ship deslop, control-cli, and control-ui copy the three skill directories in unchanged. drop the lines that said they are not bundled, and list them with the other skills. Co-authored-by: Kaitian Xie --- .agents/skills/control-cli/SKILL.md | 109 ++++++++++++++++++++++++++++ .agents/skills/control-ui/SKILL.md | 109 ++++++++++++++++++++++++++++ .agents/skills/deslop/SKILL.md | 22 ++++++ .agents/skills/poteto-help/SKILL.md | 5 +- README.md | 9 +-- docs/guide/05-build-and-clean.md | 2 +- 6 files changed, 247 insertions(+), 9 deletions(-) create mode 100644 .agents/skills/control-cli/SKILL.md create mode 100644 .agents/skills/control-ui/SKILL.md create mode 100644 .agents/skills/deslop/SKILL.md diff --git a/.agents/skills/control-cli/SKILL.md b/.agents/skills/control-cli/SKILL.md new file mode 100644 index 0000000..69289ac --- /dev/null +++ b/.agents/skills/control-cli/SKILL.md @@ -0,0 +1,109 @@ +--- +name: control-cli +description: Build or adapt a local harness to drive, inspect, and profile an interactive CLI or TUI without external services. Use for CLI UX checks, startup regressions, memory leaks, hangs, prompt flows, or terminal demos. +--- + +# Control CLI + +Use a repeatable local harness to exercise an interactive CLI instead of poking at it manually. First reuse the repo's own test/demo harness if it exists; otherwise assemble a temporary harness from standard local tools. + +## What It Is Used For + +- Reproducing CLI/TUI bugs with deterministic input. +- Verifying keyboard flows, prompts, interrupts, resize behavior, and terminal layout. +- Capturing before/after transcripts for bug fixes. +- Profiling startup time, slow operations, hangs, or memory growth. +- Recording a short terminal demo when output is easier to show than explain. + +## Harness Loop + +1. Identify the command under test and the smallest reproducible workspace. +2. Discover existing local harnesses: package scripts, e2e tests, demo recorders, expect scripts, or PTY helpers. +3. If no harness exists, launch the CLI in an isolated terminal session with deterministic env vars. +4. Capture the current screen before interacting. +5. Send one action at a time: text, Enter, arrows, Escape, Ctrl-C, resize. +6. Wait for a concrete screen pattern or prompt before the next action. +7. Save the transcript and any profile artifacts. +8. Kill the session cleanly. + +## Harness Options + +- Repo-native harness: prefer checked-in scripts because they know the app's startup, env, and prompts. +- `tmux`: managed sessions, `capture-pane`, `send-keys`, attach/detach. +- PTY probe: use a short Python, Node, or Expect script when tmux is unavailable. +- Runtime inspector: use Node or Bun inspector for CPU profiles, heap snapshots, and live evaluation. +- Terminal recorder: use repo-local demo tools or asciinema-compatible tools when the user asks for a demo. + +## Minimal tmux Harness + +```bash +SESSION="cli-harness-$(date +%s)" +tmux new-session -d -s "$SESSION" -- +tmux capture-pane -pt "$SESSION" +tmux send-keys -t "$SESSION" "help" Enter +tmux capture-pane -pt "$SESSION" +tmux kill-session -t "$SESSION" +``` + +For Node CLIs: + +```bash +NODE_OPTIONS="--inspect=127.0.0.1:0" tmux new-session -d -s "$SESSION" -- +``` + +Read the terminal output to find the inspector URL, then use Chrome DevTools-compatible tooling if profiling is needed. + +## Minimal PTY Harness + +Use a PTY script when you need deterministic waits in a repo that does not have tmux or a demo harness. Keep it temporary unless the user asks to add a reusable test. + +```python +import os +import pty +import select +import subprocess +import time + +master_fd, slave_fd = pty.openpty() +proc = subprocess.Popen( + ["", ""], + stdin=slave_fd, + stdout=slave_fd, + stderr=slave_fd, + close_fds=True, +) +os.close(slave_fd) + +deadline = time.time() + 30 +buffer = b"" +while time.time() < deadline: + ready, _, _ = select.select([master_fd], [], [], 0.25) + if not ready: + continue + chunk = os.read(master_fd, 4096) + buffer += chunk + if b"" in buffer: + os.write(master_fd, b"help\n") + break + +print(buffer.decode(errors="replace")) +proc.terminate() +os.close(master_fd) +``` + +If the CLI needs richer terminal control, use `pty.fork()` or an existing PTY library. + +## Profiling Recipes + +- Startup regression: capture baseline and treatment startup timings under the same machine, env, and command. +- Slow operation: start a CPU profile, perform the operation, stop the profile, and compare top self-time functions. +- Memory leak: force GC if available, take a heap snapshot, perform the operation repeatedly, force GC again, and take another snapshot. +- Hang: capture the screen, active handles/resources, and a stack/CPU sample before interrupting. + +## Guardrails + +- Prefer deterministic waits over sleeps. If you must sleep, explain why. +- Do not send credentials or destructive commands into a controlled session. +- Keep the harness in `/tmp` unless the repo already has a testing/demo harness. +- Do not hard-code paths from another repository. Adapt commands to the current repo's scripts and runtime. +- Clean up tmux sessions, temp dirs, inspector processes, and demo artifacts unless the user asks to keep them. diff --git a/.agents/skills/control-ui/SKILL.md b/.agents/skills/control-ui/SKILL.md new file mode 100644 index 0000000..68484fd --- /dev/null +++ b/.agents/skills/control-ui/SKILL.md @@ -0,0 +1,109 @@ +--- +name: control-ui +description: Build or adapt a local browser/CDP harness to drive and inspect a web, IDE, or Electron UI. Use for local UI verification, screenshots, accessibility snapshots, perf profiles, visual diffs, or reproducing UI bugs. +--- + +# Control UI + +Use local browser automation to verify UI behavior with evidence. First reuse the repo's own Playwright, browser, or Electron harness if it exists; otherwise assemble a temporary local harness around the app's dev server or Chromium debug port. + +## What It Is Used For + +- Reproducing UI bugs that depend on real browser focus, keyboard input, scrolling, resizing, or rendering. +- Verifying visual or accessibility changes with screenshots and snapshots. +- Checking local web, IDE, or Electron behavior before shipping. +- Capturing console logs, network logs, CPU profiles, traces, or heap snapshots. +- Creating before/after evidence for `verify-this`. + +## Setup Pattern + +1. Start the app locally using the repo's documented dev command. +2. Discover existing local harnesses: Playwright tests, Cypress specs, Storybook, browser scripts, Electron launch scripts, or snapshot tools. +3. For a web app, connect to the local URL with the existing browser tooling. +4. For Electron/Chromium, enable a remote debugging port when supported. +5. Select the correct page by stable app markers, not by tab order alone. +6. Prefer accessibility roles, labels, and stable `data-*` selectors over coordinates. + +## Generic Web Harness + +Use the repo's installed browser tooling when possible. If the repo already has Playwright, a minimal one-off probe looks like: + +```javascript +import { chromium } from "playwright"; + +const browser = await chromium.launch(); +const page = await browser.newPage({ viewport: { width: 1280, height: 800 } }); +await page.goto("http://127.0.0.1:"); +await page.getByRole("button", { name: /submit/i }).click(); +await page.screenshot({ path: "/tmp/ui-harness-after.png", fullPage: true }); +await browser.close(); +``` + +Do not add Playwright as a project dependency just for this probe unless the user asks. Prefer existing dev dependencies or external browser tools already available in the environment. + +## Generic CDP Harness + +For Electron or a Chromium app launched with `--remote-debugging-port=`, connect over CDP: + +```javascript +import { chromium } from "playwright"; + +const browser = await chromium.connectOverCDP("http://127.0.0.1:"); +const pages = browser.contexts().flatMap((context) => context.pages()); +let page; +for (const candidate of pages) { + if (await candidate.locator("").count()) { + page = candidate; + break; + } +} + +if (!page) { + console.log(await Promise.all(pages.map(async (p) => ({ + title: await p.title(), + url: p.url(), + })))); + throw new Error("No matching app page found"); +} + +await page.screenshot({ path: "/tmp/ui-harness-cdp.png", fullPage: true }); +await browser.close(); +``` + +Replace `` with a stable marker from the current repo, such as a root app node, landmark, or product-specific `data-*` attribute. + +## Interaction Loop + +1. Capture a page snapshot or screenshot before acting. +2. Choose a target from the latest page structure. +3. Perform exactly one structural action: click, type, keypress, drag, scroll, navigate, or resize. +4. Capture a fresh snapshot/screenshot. +5. Verify the expected state change. +6. Save artifacts for before/after comparisons when the user asked for proof. + +## CDP Capabilities + +Use raw CDP only when higher-level browser APIs are insufficient: + +- Performance: CPU profiles, traces, paint flashing, FPS meter, layout shift inspection. +- Memory: heap snapshots and forced GC for leak investigations. +- Network: request blocking, throttling, cache disablement, request/response logs. +- Rendering: viewport changes, color scheme emulation, reduced motion, accessibility checks. +- Debugging: console streaming, exception capture, DOM snapshots. + +## Page Selection + +When multiple app windows/tabs share a debug port: + +- Prefer a positive marker for the surface under test, such as an app root selector. +- Use a negative marker to avoid the wrong surface when necessary. +- If no page matches, list available page titles and URLs instead of guessing. + +## Guardrails + +- Do not rely on stale element references after navigation or structural changes. +- Avoid coordinate clicks unless a fresh screenshot was captured immediately before the click. +- Keep test data local and disposable. +- Do not store screenshots or heap snapshots from privacy-sensitive workspaces unless the user explicitly agrees. +- Do not hard-code selectors, ports, or script paths from another repository. Discover the current repo's local app markers. +- Clean up dev servers, debug sessions, and temp profiles when done. diff --git a/.agents/skills/deslop/SKILL.md b/.agents/skills/deslop/SKILL.md new file mode 100644 index 0000000..1b3827c --- /dev/null +++ b/.agents/skills/deslop/SKILL.md @@ -0,0 +1,22 @@ +--- +name: deslop +description: Remove AI-generated code slop and clean up code style +--- + +# Remove AI code slop + +Check the diff against main and remove AI-generated slop introduced in the branch. + +## Focus Areas + +- Extra comments that are unnecessary or inconsistent with local style +- Defensive checks or try/catch blocks that are abnormal for trusted code paths +- Casts to `any` used only to bypass type issues +- Deeply nested code that should be simplified with early returns +- Other patterns inconsistent with the file and surrounding codebase + +## Guardrails + +- Keep behavior unchanged unless fixing a clear bug. +- Prefer minimal, focused edits over broad rewrites. +- Keep the final summary concise (1-3 sentences). diff --git a/.agents/skills/poteto-help/SKILL.md b/.agents/skills/poteto-help/SKILL.md index 6a3943d..b789a43 100644 --- a/.agents/skills/poteto-help/SKILL.md +++ b/.agents/skills/poteto-help/SKILL.md @@ -39,7 +39,7 @@ When the route file is missing and it matters, ask whether the user wants to pic 2. Run [`/setup-pstack`](../setup-pstack/SKILL.md). It detects the routes DSH allows, asks for a reasoning budget, writes `~/.agents/pstack-models.md`, and checks the Subagent depth and capacity settings. Then it offers once each to generate a verification skill and a formal verification skill for the project, unless the project already has one. 3. Start a real task with `/poteto-mode`, a goal, and a check that can pass or fail. -Installing drops the skills into the catalog but changes nothing until the user invokes one. Only `/setup-pstack` is model-invocable; the rest are user-invoked or reached by a skill that reads their files. The [README](../../../README.md) and [guide page 1](../../../docs/guide/01-setup.md) have the details. Offer to word their first prompt with them, per [`references/prompting.md`](references/prompting.md). +Installing drops the skills into the catalog but changes nothing until the user invokes one. Only `/setup-pstack`, `/deslop`, `/control-cli`, and `/control-ui` are model-invocable; the rest are user-invoked or reached by a skill that reads their files. The [README](../../../README.md) and [guide page 1](../../../docs/guide/01-setup.md) have the details. Offer to word their first prompt with them, per [`references/prompting.md`](references/prompting.md). If cost is the worry, say where the tokens go and how to spend fewer. pstack spends extra tokens on subagents and review panels. Rerun `/setup-pstack` and pick a smaller budget or cheaper routes. A role set to `inherit` runs on the chat's model, which saves tokens when the chat runs on a cheaper model. A shorter panel list runs fewer subagents, one for each entry. Save `/poteto-mode` for work that needs rigor. @@ -109,7 +109,6 @@ Close calls: Not in pstack: -- `/deslop`, `control-cli`, and `control-ui` are separate skills, not bundled with pstack. Install them if you want the full set; pstack names them only when the step needs them. - `/loop` and `/create-skill` have no direct DSH equivalent. Use a DSH goal (`create_goal`) for repeated work, and the authoring playbook for skill edits. - pstack has no `/orchestrate` skill. Orchestrate is a `/poteto-mode` playbook. If the slash menu shows `/orchestrate`, another plugin provides it. @@ -138,7 +137,7 @@ Principles are one-rule skills that `/poteto-mode` reads and cites in its replie | A question got treated as the next step of the last task | Say "new task", or say the turn doesn't need the mode. | | A new model choice had no effect | The rule from `/setup-pstack` applies to new chats. Start one. | | Runs cost more than expected | See the cost paragraph under Get set up. | -| A skill didn't load on its own | Only `/setup-pstack` loads from the user's words. The others load when the user types them or when `/poteto-mode` runs them, and it doesn't run every skill. | +| A skill didn't load on its own | Only `/setup-pstack`, `/deslop`, `/control-cli`, and `/control-ui` load from the user's words. The others load when the user types them or when `/poteto-mode` runs them, and it doesn't run every skill. | | Parallel agents overwrote each other | Give each agent its own git worktree and pass its path as the child's `cwd`. DSH children share this machine. | | An overnight run moved but finished nothing | A DSH goal (`create_goal`) needs a check that can pass or fail, not a duration. See [guide page 7](../../../docs/guide/07-overnight.md). | | The reply claims success from a green build | Ask for the real command, flow, stored value, or profile. That's the prove-it-works principle. | diff --git a/README.md b/README.md index 0edae27..2ee6c05 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ dsh plugin --profile web add "github:pstack-ports/dsh-pstack" dsh --profile web ``` -`dsh plugin add` installs the package, and because it declares `dsh.bundle`, the same command appends `dsh-pstack` to the profile's bundle list. restart the profile to load the bundle. after that, `dsh-pstack` appears under Settings → Plugins, and every pstack skill appears in the `/` menu. only `/setup-pstack` is model-invocable. the other skills are user-invoked, or read by `/poteto-mode` when a step needs one. +`dsh plugin add` installs the package, and because it declares `dsh.bundle`, the same command appends `dsh-pstack` to the profile's bundle list. restart the profile to load the bundle. after that, `dsh-pstack` appears under Settings → Plugins, and every pstack skill appears in the `/` menu. only `/setup-pstack`, `/deslop`, `/control-cli`, and `/control-ui` are model-invocable. the other skills are user-invoked, or read by `/poteto-mode` when a step needs one. ### as project or user skills @@ -192,6 +192,9 @@ DSH attaches a skill to one message. pick `/poteto-mode` at the start of each ne | [`/maintain-formal-verification-skill`](./.agents/skills/maintain-formal-verification-skill/SKILL.md) | code your formal verification covers has changed since it was last checked. updates the model, harness, or properties to match the code, reruns, and says whether each failure is drift in the verification or a bug in the code. | | [`/statechart`](./.agents/skills/statechart/SKILL.md) | someone who owns the behavior needs to see it, not read a spec. draws what the user sees as a mermaid statechart generated from a tla+ model, marks each state works, still wrong, or fixed by your open pr, and draws each bug tlc finds as a numbered path. also turns an agreed chart into a tla+ skeleton, or audits the code against an existing spec. | | [`/unslop`](./.agents/skills/unslop/SKILL.md) | you're cleaning up writing. removes AI tells. | +| [`/deslop`](./.agents/skills/deslop/SKILL.md) | remove AI-generated code slop and clean up code style. | +| [`/control-cli`](./.agents/skills/control-cli/SKILL.md) | build or adapt a local harness to drive, inspect, and profile an interactive CLI or TUI. | +| [`/control-ui`](./.agents/skills/control-ui/SKILL.md) | build or adapt a local browser/CDP harness to drive and inspect a web, IDE, or Electron UI. | | [`/bro`](./.agents/skills/bro/SKILL.md) | you want the last message restated in plain human language, no jargon. | | [`/technical-writing`](./.agents/skills/technical-writing/SKILL.md) | layered doc standard (Diátaxis + Google developer style + STE + Global English) for docs, RFCs, readmes, PR descriptions, commit messages. | @@ -298,12 +301,8 @@ twenty-four short skills, one principle each. `poteto-mode` indexes them inline a few things `poteto-mode` references but doesn't bundle: -- `/deslop` and the `deslop` skill are a separate skill, not bundled here. -- `control-cli` (for CLIs and TUIs) and `control-ui` (for browser, Electron, web) are separate skills too. - `/create-skill` and `/loop` have no direct DSH equivalent. use the [authoring playbook](./.agents/skills/poteto-mode/playbooks/authoring-a-skill.md) for skill edits, and a DSH goal (`create_goal`) for repeated work. DSH also has no built-in `/autopilot` that watches a PR. inside `poteto-mode`, pr-status requests go to the [babysit playbook](./.agents/skills/poteto-mode/playbooks/babysit.md). -install those companion skills alongside pstack if you want the full set. - ## why are there no planning skills? DSH already has a great plan mode which works great with pstack. but personally, i don't believe in planning. the best spec is code. if you do want to make a plan, [`/poteto-mode`](./.agents/skills/poteto-mode/SKILL.md) covers it, but it's not a default. diff --git a/docs/guide/05-build-and-clean.md b/docs/guide/05-build-and-clean.md index 6587835..7ce7ee0 100644 --- a/docs/guide/05-build-and-clean.md +++ b/docs/guide/05-build-and-clean.md @@ -56,7 +56,7 @@ In context, that's enough. [`/tdd`](../../.agents/skills/tdd/SKILL.md) writes th ## Clean before you commit -The [Opening a PR playbook](../../.agents/skills/poteto-mode/playbooks/opening-a-pr.md) runs `/deslop` on the diff before each commit and applies [`/unslop`](../../.agents/skills/unslop/SKILL.md) to the PR description and commit bodies. `/deslop` is a separate skill, not bundled with pstack. If you don't have it, ask for the same outcome in plain words: remove narrating comments, unsupported guards, dead compatibility paths, and unrelated edits. +The [Opening a PR playbook](../../.agents/skills/poteto-mode/playbooks/opening-a-pr.md) runs [`/deslop`](../../.agents/skills/deslop/SKILL.md) on the diff before each commit and applies [`/unslop`](../../.agents/skills/unslop/SKILL.md) to the PR description and commit bodies. If you don't have it, ask for the same outcome in plain words: remove narrating comments, unsupported guards, dead compatibility paths, and unrelated edits. For prose, `/unslop` takes a target and any extra rules you have: From 0c83f7381213de7c93d26cc7d0a3c2eb0f53101a Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Tue, 27 Oct 2026 00:47:35 +0000 Subject: [PATCH 2/2] keep /deslop unlinked in the build guide drop only the sentence that said it was not bundled. Co-authored-by: Kaitian Xie --- docs/guide/05-build-and-clean.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/05-build-and-clean.md b/docs/guide/05-build-and-clean.md index 7ce7ee0..0f2c665 100644 --- a/docs/guide/05-build-and-clean.md +++ b/docs/guide/05-build-and-clean.md @@ -56,7 +56,7 @@ In context, that's enough. [`/tdd`](../../.agents/skills/tdd/SKILL.md) writes th ## Clean before you commit -The [Opening a PR playbook](../../.agents/skills/poteto-mode/playbooks/opening-a-pr.md) runs [`/deslop`](../../.agents/skills/deslop/SKILL.md) on the diff before each commit and applies [`/unslop`](../../.agents/skills/unslop/SKILL.md) to the PR description and commit bodies. If you don't have it, ask for the same outcome in plain words: remove narrating comments, unsupported guards, dead compatibility paths, and unrelated edits. +The [Opening a PR playbook](../../.agents/skills/poteto-mode/playbooks/opening-a-pr.md) runs `/deslop` on the diff before each commit and applies [`/unslop`](../../.agents/skills/unslop/SKILL.md) to the PR description and commit bodies. If you don't have it, ask for the same outcome in plain words: remove narrating comments, unsupported guards, dead compatibility paths, and unrelated edits. For prose, `/unslop` takes a target and any extra rules you have: