Repository navigation
fix(pstack): make a brand with a type guard, not as - #700
Merged
Merged
Conversation
The branded-type example built its brand with `as`, which the skill's "No `as` casts" row tells agents to avoid. parseAgentId now narrows through an isAgentId type guard and returns the input with no cast, and the Branded types row says a brand comes from a verifying type guard, never from `as`.
poteto
marked this pull request as ready for review
October 17, 2026 19:06
caelaxie
added a commit
to pstack-ports/devin-pstack
that referenced
this pull request
Oct 18, 2026
<!-- CURSOR_AGENT_PR_BODY_BEGIN --> baseline `2418e86` matches upstream pstack at [`e5136d8`](cursor/plugins@e5136d8) ([#633](cursor/plugins#633)). diffed the baseline tree against `pstack/` at `e5136d8` and at its parent `850d7f2`. the parent still has the pre-#633 principle text. the only path in `e5136d8` that the baseline lacks is `pstack/.cursor-plugin/`, which this port never carried (devin uses `.devin-plugin/plugin.json`). upstream `main` has no pstack commits after `019a6a2`. version is still `0.15.25` upstream, so plugin.json, `.devin-plugin/plugin.json`, and the readme stay at `0.15.25`. synced to `019a6a20592c10bf92869e5740368f578a9997fd`. ported: - [`99743e9`](cursor/plugins@99743e9) ([#634](cursor/plugins#634)) cut marginal sections from `interrogate/references/lead-judgment.md`, `principle-migrate-callers-then-delete-legacy-apis`, `principle-type-system-discipline`, and `swarm`. kept the existing devin frontmatter (`triggers: [user]`) and the existing devin swarm wording. the #634 readme table edit drops "refuse to lie to the compiler" from the upstream principle index. this port's readme no longer has that index, and the phrase lived only in the skill description, which is updated. - [`0317eb8`](cursor/plugins@0317eb8) ([#700](cursor/plugins#700)) brand via a type guard in `typescript-best-practices` `SKILL.md` and `references/patterns.md`. kept `triggers: [user, model]` and the dropped `paths` frontmatter. - [`a968159`](cursor/plugins@a968159) ([#702](cursor/plugins#702)) `poteto-mode` frontmatter `name` is now `poteto-mode`. `make-bot-ui` already had `name: make-bot-ui` from the devin port. other skills already matched their folders. - [`019a6a2`](cursor/plugins@019a6a2) ([#704](cursor/plugins#704)) guide prose and the autopilot-full claim in `docs/guide/02` through `10`. kept existing devin wording (`/pstack:` prefixes, cloud sessions, `.devin` paths). skipped: - [`e5136d8`](cursor/plugins@e5136d8) ([#633](cursor/plugins#633)) is already the baseline. - [`182f2ce`](cursor/plugins@182f2ce) ([#637](cursor/plugins#637)) is claude code generated-tree install. core `pstack/skills` is unchanged. the "benny is cursor-only" sentence is skipped because this port already runs benny as devin sessions. - [`a968159`](cursor/plugins@a968159) generator check in `scripts/generate-pstack-harness-trees.mjs`. that script builds the claude code tree and does not apply to this repo. - [`1b80080`](cursor/plugins@1b80080) ([#705](cursor/plugins#705)) is claude code packaging. it edits `docs/harness/claude-code.md`, the generated `harness/pstack/claude-code` tree, the generator, and the claude code install blurb in the upstream readme. no skill text under `pstack/skills` changes. this port has no claude code adapter. - [`019a6a2`](cursor/plugins@019a6a2) `scripts/check-pstack-docs.mjs` and the regenerated claude code copies. the check hardcodes a `pstack/` subdirectory, the full upstream readme tables, and a sibling `cursor-team-kit`. this repo is the plugin at the root with a short devin readme, so the script does not apply as-is. the upstream readme edits that only touch the claude code install blurb, the cursor custom-mode paragraph, and the built-in `/babysit` to `/autopilot` rename are also skipped. this port's readme does not have those sections, and `docs/guide/01-setup.md` already tells devin to pin the style in `AGENTS.md` instead of a cursor custom mode. the autopilot-full claim from that readme table is ported in `docs/guide/07-overnight.md`. <!-- CURSOR_AGENT_PR_BODY_END --> <div><a href="https://cursor.com/agents/bc-5e99de38-babb-516d-92d0-296b6550796a?cursor_ref=pr_footer&cursor_cta=open_in_web"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-web-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-web-light.png"><img alt="Open in Web" width="114" height="28" src="https://cursor.com/assets/images/open-in-web-dark.png"></picture></a> <a href="https://cursor.com/background-agent?bcId=bc-5e99de38-babb-516d-92d0-296b6550796a&cursor_ref=pr_footer&cursor_cta=open_in_cursor"><picture><source media="(prefers-color-scheme: dark)" srcset="https://cursor.com/assets/images/open-in-cursor-dark.png"><source media="(prefers-color-scheme: light)" srcset="https://cursor.com/assets/images/open-in-cursor-light.png"><img alt="Open in Cursor" width="131" height="28" src="https://cursor.com/assets/images/open-in-cursor-dark.png"></picture></a> </div> --------- Co-authored-by: Cursor Agent <cursoragent@cursor.com> Co-authored-by: Kaitian Xie <caelaxie@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
The branded-type example in
typescript-best-practicesbuilt its brand withreturn input as AgentId, which the skill's "Noascasts" row tells agents to avoid. Agents copy the example, so it taught the cast the rules forbid.What changed
parseAgentIdnow narrows through anisAgentIdtype guard and returns the input with no cast.input is AgentId), never fromas.Scope
pstack/skills/typescript-best-practicesand its regenerated Claude Code copy.asafter validation.Blast Radius
Only the text agents read for TypeScript edits changes. No code, build, or runtime path changes.
Verification
asand no errors. It still rejects a raw string where anAgentIdis expected.node scripts/validate-plugins.mjspasses, andnode scripts/generate-pstack-harness-trees.mjs --checkreports the harness tree up to date.Note
Low Risk
Documentation-only changes to agent skill text; no application code, build, or runtime behavior.
Overview
Aligns the typescript-best-practices branded-type guidance with the skill’s own No
ascasts rule so agents don’t copy a forbidden pattern.The Branded types table row now states that a brand must come from a verifying type guard (
input is AgentId), not fromas. Thepatterns.mdexample addsisAgentId, uses it inparseAgentId, and returns the narrowed string without a cast.Reviewed by Cursor Bugbot for commit 4c18caa. Bugbot is set up for automated code reviews on this repo. Configure here.