mirror of
https://github.com/obra/superpowers.git
synced 2026-11-06 06:30:21 +00:00
1045 commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
df2e996a17 | Merge main back into dev after the v7.0.2 release | ||
|
|
22f0b463e7
|
Release v7.0.2: brainstorming tuning, harness bootstrap fixes, SDD helper fixes (#2657)
* docs: reduce Hermes version-bump design
Incorporate the adversarial design review without turning the Hermes wiring follow-up into a general release-script refactor. Keep the existing jq path, add Mike Farah yq v4 only for .yaml, and retain one read-only preflight to prevent deterministic partial bumps.\n\nReduce the test contract to three behavioral cases and explicitly defer .yml support, nested YAML, rollback machinery, audit/status redesign, exhaustive failure matrices, and the separately discovered JSON-expression issue. This follows Drew's direction to avoid ceremony and overengineering.
* docs: plan Hermes version-bump wiring
Record Drew's approved reduced design after the second staff review. Limit preflight to the mutating bump path, cover audit's independent read path, and require byte-for-byte proof that deterministic YAML failures cannot partially update earlier JSON manifests.
Provide one TDD implementation task for the Hermes registry entry, jq/yq dispatch, focused preflight, and three behavioral checks. Explicitly defer rollback, audit-status changes, nested YAML, runtime changes, and broader release-tool refactoring.
* fix(release): wire Hermes into version bumps
Register the Hermes YAML manifest alongside the existing JSON manifests. Route manifest reads and writes by extension through jq or Mike Farah yq v4, with field names and values passed as data.
Preflight every present manifest before the mutating bump loop so a deterministic YAML read failure cannot leave earlier JSON manifests partially updated. Cover check, audit, bump, registry wiring, and byte-for-byte no-partial-write behavior with one focused fixture test.
* feat(opencode): add V2 (opencode2) plugin compatibility
Add dual V1/V2 support to the OpenCode plugin. The same source file now
works on both OpenCode V1 (opencode) and V2 (opencode2) without version
detection at runtime.
V2 changes:
- Add default export { id, server, setup } for V2 PluginSupervisor
- setup() registers skills via ctx.skill.transform() (V2 native API)
- setup() injects bootstrap via ctx.session.hook('context') (V2 equivalent
of V1's experimental.chat.messages.transform)
- config hook guards against V2 array-format skills to avoid conflicts
Both APIs confirmed active at runtime via diagnostics in the V2 beta.
No external dependencies added — pure JavaScript throughout.
Docs updated with V2 install instructions, OPENCODE_CONFIG_DIR side-by-side
setup, and accurate How It Works section for both versions.
* docs: add Grok Build CLI to README.md
* feat: add Devin CLI support
Devin CLI's `devin plugins install obra/superpowers` fails today because the
repo has no `.devin-plugin/plugin.json` manifest. Add the manifest (skills are
auto-discovered from the co-located skills/ directory), a Devin tool mapping
linked from using-superpowers' Platform Adaptation section, a README install
section, version tracking in .version-bump.json, a Codex-sync exclude for the
new dotdir, and a CI-safe test mirroring the kimi/antigravity test style.
Bootstrap rides Devin's native skill surfacing: every installed skill's
name + description is injected into the system prompt at session start with a
standing instruction to invoke matching skills via the native skill tool.
Acceptance test ("Let's make a react todo list") passes in a clean session:
using-superpowers and brainstorming auto-trigger before any code is written.
* Drop devin-tools.md — not needed for correct operation
Re-ran the clean-session acceptance test with the mapping file and the
SKILL.md Platform Adaptation pointer removed: using-superpowers and
brainstorming still auto-trigger first, and the full workflow chain
(writing-plans, executing-plans, TDD, verification) resolves every action
to Devin's native tools. Devin CLI's own system prompt already documents
its tools (skill invocation, subagent profiles, todo tracking, question
prompts), so the mapping was redundant. Test now validates the manifest only.
* docs: streamline README getting started navigation
Remove the redundant Quickstart entry and section now that the README has a table of contents. Rename the Installation label in the table of contents to Getting Started while retaining the existing installation anchor and section heading.
* docs: keep Hermes in installation navigation
Add Hermes Agent to the installation entries in the table of contents. The removed Quickstart section was the README's only direct link to that existing installation section, so preserving the link avoids a navigation regression.
* feat(tdd): the project's suite defines green, not just your test file
At the Verify GREEN moment, redefine "other tests still pass": run the
project's test command even when the task named only one test file — a
scope statement bounds the deliverable, not the verification — and any
failure seen goes in the report by name. In a pre-registered 24-rep
battery on an adjacent-breakage probe, controls ran the wider suite in
1/12 sessions; with this text, 8/12 (sonnet 4/4, kimi 3/4, glm 1/4),
and every session that saw the failure reported it.
Claude-Session: https://claude.ai/code/session_0185AJr98gHx5EmwqNeft4Sy
* docs: release notes for v6.3.0
* chore: bump version to 6.3.0
* Update to Prime Radiant Community Code of Conduct. (#2122)
* docs: add Qwen Code install instructions to README
Rebased from PR #2108 onto the reworked README. Differences from the PR:
the Hermes TOC entry and Quickstart-line changes are obsolete (the v6.3.0
README rework already added the former and removed the latter), and the
Hermes post-compaction caveat stays: .hermes-plugin injects the bootstrap
only on is_first_turn, so the caveat is still accurate.
Install/update commands and the acceptance transcript are from PR #2108
(@arittr, tested interactively on Qwen Code).
Co-authored-by: Drew Ritter <arittr@users.noreply.github.com>
* fix(requesting-code-review): anchor the multi-commit BASE_SHA alternative to the merge base
The '# or origin/main' alternative fed a moving ref into the reviewer's
two-dot diff: once origin/main advances past the branch point, main's new
files appear as phantom deletions the reviewer can't distinguish from real
ones. Reproduced during triage (2026-08-12): a scratch repo with main
advanced one commit shows 'main-new.txt | 1 -' in the branch's diff.
git merge-base origin/main HEAD anchors the range to the branch point,
matching how sdd's review-package already computes BASE.
Reported in #2118 (wan-huiyan). Fixes #2118.
* fix(sdd): invoke sdd-workspace via bash so helpers survive stripped exec bits
Codex marketplace users hit 'Permission denied' running SDD helpers:
some extractors (Python zipfile) discard Unix mode attributes when
unpacking the package, so task-brief's and review-package's direct exec
of their sibling sdd-workspace fails. Our packaging preserves 0755
(git archive | tar -xpf, asserted by the existing packaging test) — the
bits are lost on the consumer side, which no packaging change can reach.
Invoking the sibling via "${BASH:-bash}" makes the exec bit irrelevant.
TDD: new regression case copies the helpers, chmod -x, runs task-brief
via bash — RED with the reported rc=126 Permission denied, GREEN after.
Reported in #2040 (michaelholcomb-creator). Fixes #2040.
* fix(sdd): reject empty or non-descendant BASE..HEAD ranges in review-package
When an SDD implementer commits to the wrong branch (#2050), the
BASE..HEAD range handed to review-package is either empty or not rooted
at BASE. Both cases previously produced a review package silently —
an empty one lets the reviewer approve "clean" work that isn't there.
Add two mechanical guards after BASE/HEAD validation, exiting 3 (vs 2
for usage errors) so callers can distinguish range problems:
- git merge-base --is-ancestor BASE HEAD, else "HEAD is not a
descendant of BASE"
- git rev-list --count BASE..HEAD > 0, else "empty commit range"
Guard shape credits the analysis in closed PR #2082 by @stantheman0128.
Fixes #2050
* fix(opencode): adapt to V2 skill draft API removal (#2106)
OpenCode V2 removed SkillDraft.source() in 1113adfd5e (#41622): the
skill service now stores values only, and filesystem scanning moved to
the config side. The plugin's draft.source({type:'directory'}) call
threw 'draft.source is not a function', which killed the entire V2
plugin activation generation. Because V2 gates model.list on
PluginSupervisor.flush (23b0688a7f, #41783), that failure left flush
pending forever and the TUI showed no providers or models
('Model catalog initialization timed out', /api/model 503).
Register each skills/<name>/SKILL.md as a native Skill.Info object via
draft.add({id, name, description, location, content}) instead, matching
the {list, add, update, remove} draft API and the pattern used by
V2's built-in skill plugin. Wrap skill registration, hook registration,
and the context hook callback in try/catch so a future V2 API change
degrades to a logged error instead of taking down the whole generation
again. session.hook('context') payload shape is unchanged and keeps
working.
Verified end-to-end on opencode2 v0.0.0-beta-17595: 24 skills listed
via /api/skill (all superpowers skills present), /api/model returns
83 models across 3 providers, no 'failed to reload plugins' in server
logs. V1 path untouched.
* fix(opencode): skip V2 setup when V1 invokes it with a V1-shaped ctx
opencode 1.18.18 also calls default.setup, but with a ctx that lacks
the skill/session domains, so the defensive try/catch logged a TypeError
into every V1 session transcript even though V1 is fully served by the
SuperpowersPlugin named export. Detect the V1 shape and return quietly.
* feat(skills): import proving-it-works-with-a-movie from its standalone repo
Brings the proving-it-works-with-a-movie skill (demo/screencast/proof-video
recording, plus the check-movie timeline gate that catches frozen pictures,
narration drift, and dropped words) into superpowers core, along with its
supporting docs, scripts, and shell regression tests.
Source: prime-radiant-inc/proving-it-works (MIT, same copyright holder),
skills/proving-it-works-with-a-movie/ at time of import. The five scripts
(narrate, make-subtitles, assemble, burn-subtitles, check-movie) are
self-contained uv --script files with inline PEP 723 dependency
declarations, so they port with no new project-level dependency wiring.
Test paths were adjusted one directory level to match superpowers'
tests/<skill-name>/ layout (the standalone repo kept tests/ as a
top-level sibling of skills/).
Adds a Verification entry to README's Skills Library list.
Goal: fold this into 6.4 and retire the standalone repo.
* fix(opencode): skip controller bootstrap in task subagent sessions (#2160)
Detect child sessions structurally via session parentID instead of
relying on the model honoring <SUBAGENT-STOP>:
- V1: sessionID from firstUser.info.sessionID (hook input is empty at
runtime), parentID via client.session.get({path:{id}})
- V2: sessionID from the context-hook event, parentID via
ctx.session.get({sessionID})
Decision cached per session; lookup failures fail open (previous
behavior) and are not cached. Skills registration is unaffected, so
workers keep explicit access to execution skills.
* fix(opencode): skip controller bootstrap in task subagent sessions (#2160)
The messages.transform hook injects the using-superpowers bootstrap into
the first user message of every session, including task subagent
children. Workers then restart brainstorming/design cycles for work the
parent already authorised — the <SUBAGENT-STOP> note inside the
bootstrap only works when the model chooses to honor it.
Detect child sessions structurally instead: OpenCode task sessions are
created with a parentID, so when the session carrying the message has a
parentID, skip bootstrap injection. The hook receives no input at
runtime (verified in the 1.18.x bundle: trigger(..., {}, {messages})),
so the sessionID is taken from firstUser.info.sessionID and the session
record is fetched via client.session.get({path:{id}}).
The decision is cached per session; lookup failures fail open (previous
inject-always behavior) and are not cached so transient errors recover.
Skills registration is untouched — workers keep explicit access to
execution skills.
* fix(opencode): add root index.js entrypoint for v2 directory-form registration
* docs(opencode): remove and merge identical v1/v2 install and update guidance
* Fix platform-support issue template to apply a label that exists
The template auto-applies `platform-support`, but the repo has no such label
(harness requests use `new-harness`). GitHub silently drops labels that don't
exist, so every platform-support request arrives unlabeled — the Amazon Q
request (#2194) is the latest example.
Claude-Session: https://claude.ai/code/session_01UiEfXTZAC5cuH4hgx24mbB
* fix: establish shared intent before implementation
Discover the intended outcome, audience and success criteria before proposing
features when the request leaves them unclear. Reflect the understanding for
correction and carry it into the selected path's design artifact.
Bind approval to the actual stage presented: new architectural work requires
written-spec review and the planning handoff before implementation. Preserve
the existing lighter spike and bounded paths and clarify the short-design
example accordingly.
Jesse requested this repair after a React todo session advanced from feature
scope approval without establishing purpose. The controlled CLI comparison
observed purpose discovery in 5/5 candidate openings versus 0/5 controls, with
full-chain and holdout outcomes and their limits recorded in the PR. This
commit preserves the independently reviewed skill bytes; research artifacts
and the original development history are archived outside the PR.
* fix: review the saved plan before execution
Present the saved, self-reviewed plan for human review before implementation.
Request an execution method when none was supplied; preserve an existing
choice and ask only for plan review when the human already chose a method.
This completes the shared-intent repair without interpreting approval of an
earlier idea or scope as approval of an unseen implementation plan. Four
saved-plan smoke cases covered old/new wording with/without a prior choice;
all passed the narrower handoff checks, including old controls, so this is
not evidence of measured improvement.
Jesse requested consolidation into two commits and removal of the supporting
spec/plan research content from the PR. The skill bytes remain identical to
the reviewed branch; the complete research and original history are retained
in local archives.
* docs: specify proof movie OS compatibility
* docs: resolve adversarial review of movie compatibility spec
* docs: plan proof movie OS compatibility with Windows validation host
* test(movie): validate native Windows recording mechanism
* fix(movie): release probe resources after evidence failures
* docs(movie): avoid repeating the interactive probe take
* test(movie): port regression fixtures to Python
* test(movie): verify first subtitle cue offset
* fix(opencode): differentiate tool mapping by host flavor and harden child detection
Current opencode2 builds renamed the model-facing tools (bash→shell,
task→subagent with `agent` instead of `subagent_type`, apply_patch→
patch/patchText) and removed todowrite entirely, so the single v1
mapping injected on v2 hosts taught the model stale tool names.
- export V1_MAPPING/V2_MAPPING and inject the flavor-correct one on
each path (v1 messages.transform → V1; v2 ctx.session.hook("context")
→ V2, incl. no-todo-tool guidance and sessionID continuation)
- child-session detection now keys on parentID presence (primary
signal on both flavors) with dual-shape unwrapping preserved; v1
#2160 behavior unchanged
- mirror surfaces updated: INSTALL.md dual mapping tables,
README.opencode.md host-flavor notes, test-bootstrap-caching.mjs
asserts both mappings + drives the v2 context hook end-to-end
- skills: add OpenCode to executing-plans' subagent-capable list,
accurate OpenCode worktree status (git fallback; TUI dialogs are
user-side only), generalized live-subagent resume guidance
* fix(movie): make frame and concat inputs portable
* docs: scope remaining movie work to Windows completion
* docs: resolve adversarial review of Windows completion scope
* docs: plan three milestones to finish Windows movie support
* fix(opencode): drop skill-content edits from this PR
AGENTS.md requires evaluated adversarial testing for any skill-content
change; these three one-line harness-accuracy notes don't clear that
bar, so they are deferred to a separate evaluated change. The PR now
ships plugin, docs, and test changes only — no skill content modified.
* fix(movie): finish native Windows media tools
* feat(movie): support native Windows terminal recording
* fix(movie): verify terminal health before finalizing takes
* docs(movie): document and verify Windows workflows
* docs(movie): correct reserved regression suite names
* chore(movie): drop the abandoned OS-rollout probe and superseded plans
The first, broader OS-compatibility rollout was stopped and replaced by the
narrower Windows completion. Its feasibility probe, probe cleanup test,
design, review, 12-task plan, results report, and the completion plan and
review record were internal execution artifacts with machine-specific paths.
The one probe-derived test list is inlined into the terminal suite.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test(movie): keep one portable test suite
The Python suite ported the three shell tests' assertions so they run on
Windows; both copies were kept and the README mapped one to the other. Keep
the portable suite. Drop the one-shot Windows acceptance driver and its
browser fixture, which produced evidence rather than regressions, and the
never-implemented reserved suite names.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* docs(movie): trim Windows guidance to what the tools need
Remove generic shell exit-status recipes and a stills wrapper that the card
scene already covers. Keep the gdigrab commands and the verify-on notes
short. Reduce the spec to the design: drop execution logistics, host names,
and references to deleted files.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* test(movie): keep tool output out of the test log
The in-process narration and subtitle tests let the tools' stdout and
stderr through to the runner. Capture both and assert the expected
diagnostics.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* feat(movie): simplify the Windows terminal recorder to serve/run/key/watch/close
Windows has no tmux, so the recorder had grown into a 738-line daemon with a
file-based request protocol, request IDs, wait-only result retrieval, and a
Win32 Job Object module. Replace it with the Unix route's shape: serve keeps
ttyd and a headless browser alive and logs the terminal's output; run, key,
watch, and close are one-shot CDP calls against that browser. The installed
prompt reports each command's status through the window title, so run can
print it without any visible marker.
Process cleanup uses taskkill /T (a pgrep walk on Unix) instead of Job
Objects, which also simplifies the card renderer. The session tests run on
macOS too, since nothing in the script is Windows-specific.
Verified: 9 session tests per shell on Windows 11 for PowerShell 5.1,
PowerShell 7, and Git Bash; the browser suite with Chrome and Edge; 44
portable tests on macOS against a real ttyd session.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
* feat: add diagnosing-superpowers skill
Evidence-based diagnosis of superpowers sessions: intake with the human
partner, safe transcript reading for Claude Code and Codex (discovery
procedure for other harnesses), seven analyst subagents, a report with
path:line evidence and a bounded superpowers-involvement line, scrubbed
export bundles, approval-gated GitHub issue search/draft, and
similar-session search. Includes spec, plan, structure test, and README
and docs index lines.
Developed RED-GREEN-REFACTOR per writing-skills: 46 scored scenario runs
across five SKILL.md versions, all twelve scenarios clean against the
final version, micro-tests control 5/5 to skill 0/5 on both
baseline-failing prohibitions, and one end-to-end run. Eval records are
kept by the maintainer outside the repo.
Claude-Session: https://claude.ai/code/session_01DyaGKhTXvHNs2JgPhDktz7
* docs: add 'When Something Goes Wrong' README section for diagnosing-superpowers
* diagnosing-superpowers: build the scrubbed bundle only on request
Never build or push a bundle unprompted. When intake names a bug report as
the goal, say once that a bundle is available on request, then wait. On
handover, state what the bundle contains, point at the scrub log, and say
scrubbing can miss things so every file needs review before sharing.
Raise the SKILL.md word budget to 1000 to fit the added rule.
* diagnosing-superpowers: share the analyst preamble and context-safety rules
The seven analyst prompts opened with an identical 39-line block (role,
inputs, context safety, return format). It now lives once in
prompts/analyst-common.md and each dimension prompt points at it. The
wc -lc / long-line / never-cat rule was restated in nine places; it now
lives in references/context-safety.md and everything else points there.
Addresses arittr's review on #2236.
* diagnosing-superpowers: drop gh; file issues through a prefilled template link
A default gh login carries the repo scope, which is write access to every
repository the user can reach. The skill now searches issues through the
unauthenticated public API and, instead of posting, hands the partner a
prefilled new-issue link. The link uses a new diagnosis_report.md issue
template so the bug and automated-issue-report labels apply regardless of
the reporter's permissions. Addresses arittr's review on #2236.
* diagnosing-superpowers: say 'plan step', not 'commitment'
In a transcript full of git commits, 'commitment' and 'committed to' read
as version control. The plan-adherence and quality-evidence prompts now
say 'agreed plan' and 'plan step'.
* spec: 'agreed to', not 'committed to', in the plan-adherence summary
* diagnosing-superpowers: writing review fixes
Move GitHub search and prefilled-link mechanics to references/github-issues.md.
State the redaction levels neutrally instead of nudging toward more data.
Say that all seven analysts always run and what the quick-reference table
is for. Add a title slot and a bundle slot to the issue template. Drop the
duplicated human-prompts rule from request-conflicts. Prose fixes: active
voice, dangling modifier, vague referents, two lists turned into tables.
* diagnosing-superpowers: use gh for issue search and creation
gh handles auth, rate limits, and JSON, and the approval gate on the
exact issue text already covers posting. Keep the public-API and
prefilled-link paths as fallbacks for machines without gh. Note that
GitHub drops labels from reporters without push access, so the template
footer is the durable marker of a skill-filed issue.
* Use shared session discovery in diagnosing-superpowers
At Drew's request, apply the evaluated shared-discovery variant to Jesse's
existing PR #2236. Resolve native session sources and record semantics from
available tools, documentation and bounded inspection. Record verified absolute
paths, linkage, extraction queries, human-message distinctions, usage-counter
semantics and uncertainty once in the case for all analysts to consume.
Replace the three per-harness references and update structural checks.
This is exactly the evaluated source tree at
|
||
|
|
78c867996a |
test(brainstorm-server): drain the socket before counting reloads
The two "does NOT send reload" tests waited for the barrier file's screen-added line on stdout, then counted reloads on the WebSocket. The server logs and broadcasts in the same tick, but stdout and the socket are separate channels, and on Linux stdout usually won: the socket had 0 reloads when the barrier fired and 1 reload 300ms later, so the tests failed in 8 of 10 runs. They now ping the server after the barrier and wait for the pong. The server writes it on the same socket after the reload, so every reload sent before it has arrived. 30 consecutive clean runs; with the server's .html filter removed, both tests still fail. |
||
|
|
e82bda4639 | chore: bump version to 7.0.2 | ||
|
|
ae033c96bf
|
Merge pull request #2656 from obra/docs/release-notes-7.0.2
docs(release-notes): draft v7.0.2 notes |
||
|
|
76644f09d0 | docs(release-notes): v7.0.2 lead says brainstorming is further tuned | ||
|
|
133f38b2a8 |
docs(release-notes): draft v7.0.2 notes
Covers the nineteen PRs merged into dev since v7.0.1 and keeps the Muse entry that was under Unreleased. |
||
|
|
43685181dd
|
Merge pull request #2654 from obra/fix/2277-systematic-debugging-fixtures
fix(systematic-debugging): ship pressure scenarios under tests/, not in the skill (#2277) |
||
|
|
4be1ee9247
|
Merge pull request #2644 from obra/fix/brainstorming-questions-earn-their-place
brainstorming: ask why first, no filler questions, a design to react to (#2530) |
||
|
|
cdeb32c955
|
Merge pull request #2609 from obra/fix/codex-scripts-in-worktrees
fix(codex): accept linked git worktrees in the package and sync scripts |
||
|
|
4e08cb1469
|
Merge pull request #2608 from obra/fix/2524-relative-project-dir
fix(brainstorming): resolve a relative --project-dir before start-server.sh cds (#2524) |
||
|
|
95b0413050
|
Merge pull request #2607 from obra/fix/2429-sdd-invocation-text
skills(sdd, executing-plans): run helpers by absolute path from the working tree (#2429, #2525) |
||
|
|
2f5dc3b335
|
Merge pull request #2606 from obra/fix/2429-sdd-repo-resolution
fix(sdd): helpers act on the current directory's repo like git, with -C to override (#2429) |
||
|
|
862308e2b3
|
Merge pull request #2605 from obra/fix/2436-task-brief-unclosed-fence
fix(sdd): task-brief refuses a brief that an unclosed code fence would run to EOF (#2436) |
||
|
|
6aeac7ed95
|
Merge pull request #2604 from obra/fix/2459-2496-task-brief-headings
fix(sdd): task-brief finds alphanumeric task IDs and explains non-English headings (#2459, #2496) |
||
|
|
7166b468f6
|
Merge pull request #2602 from obra/fix/2307-sdd-scripts-windows
fix(sdd): print a Windows-readable workspace path (#2307) |
||
|
|
ca5ba4e5c9
|
Merge pull request #2601 from obra/fix/2391-opencode-compaction-bootstrap
fix(opencode): inject the V2 bootstrap on compaction and generate requests |
||
|
|
38fd8323e4 |
Merge dev into the OpenCode compaction bootstrap fix
Drew requested resolution of the merge conflict in obra/superpowers PR #2601. Merge current dev into the existing PR branch without rewriting its history. Resolve the V2 bootstrap hunk by keeping #2601's shared handler registered on context, compaction, and generate, and incorporating #2600's exact BOOTSTRAP_MARKER prefix guard. This preserves injection for prompts that merely mention EXTREMELY_IMPORTANT while preventing duplicate bootstrap parts. All other dev changes merge without manual edits. Validation: bash tests/opencode/run-tests.sh passed all five suites, including hook registration, tag-mention regression coverage, child-session suppression, caching, and skill registration. git diff --cached --check passed and the index contains no unresolved paths. Live OpenCode integration sessions were not rerun for this conflict-only repair. Tracking: PRI-3674 |
||
|
|
587f04636d
|
Merge pull request #2600 from obra/fix/2197-opencode-bootstrap-guard
fix(opencode): don't mistake a prompt that mentions EXTREMELY_IMPORTANT for the bootstrap |
||
|
|
31ac34e181
|
Merge pull request #2597 from obra/fix/2583-opencode-skill-names
fix(opencode): tell the model skill ids are bare names (#2583) |
||
|
|
d77032086f
|
Merge pull request #2596 from obra/fix/2536-hermes-child-bootstrap
fix(hermes): skip the controller bootstrap for delegate_task children (#2536) |
||
|
|
352652109f
|
Merge pull request #2595 from obra/fix/2083-pi-bootstrap-every-turn
fix(pi): inject the bootstrap on every prompt, not just the first (#2083) |
||
|
|
4eb73b6b70 |
fix(systematic-debugging): ship pressure scenarios under tests/, not in the skill (#2277)
systematic-debugging installed CREATION-LOG.md and four pressure-test scenarios next to SKILL.md. Nothing in the skill links them, but agents read and grep installed skill directories, and the scenarios open with "This is a real scenario. You must choose and act". Move all five, unchanged, to tests/systematic-debugging/pressure-scenarios/, and add tests/skill-layout/test-no-dev-files-in-skills.sh, which fails if any skill directory ships a CREATION-LOG.md or a test-*.md file. |
||
|
|
e8cc5c9c4c |
brainstorming: ask why first, ask no filler, put a design in front of them (#2530)
7.0.1 brainstorming ends every message with a question and re-asks what the request already settled (#2530). Blind-graded simulated conversations showed the filler, and also that cutting it naively costs the "why" conversation the skill exists for. - Ask a question only when the answer changes what gets built and nothing already answers it; otherwise state the call as a proposal. - Ask why first when they haven't said, as an open question; once the why is known, lay out nameable choices as concrete sketches with a pick. - Process steps (writing up, file locations, recon, how to show something) are the agent's calls, stated rather than asked. The visual companion is offered when the look itself is theirs to decide. - Read technical appetite from how they talk: options for people who raise the how, stated calls for people who talk outcomes. - When nothing is open as the first message is written and there's one sensible way, that message carries the short design for approval. The step list and its Red Flag row allow only that case. Frontmatter description, skip offer and design gate are unchanged. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
f713233eee |
fix(codex): accept linked git worktrees as checkouts
package-codex-plugin.sh and sync-to-codex-plugin.sh checked for a checkout with [[ -d .git ]]. In a linked worktree .git is a file, so both scripts died with "not a git checkout" there, and tests/codex/test-package-codex-plugin.sh failed 9 checks when run from any worktree. Test that .git exists instead: it covers both layouts and still requires the path to be the root of a checkout, which matters for sync's user-supplied --local path. The scripts' later git commands already work in worktrees. Regression tests run the package script from a linked worktree of the repo, and a sync preview from a linked upstream worktree into a linked destination worktree. The package test is adapted from #1910. Co-authored-by: tianma-if <tianma-if@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
fa50d836bf |
brainstorming: resolve a relative --project-dir before start-server.sh cds
start-server.sh built SESSION_DIR, PID_FILE, LOG_FILE and BRAINSTORM_DIR from --project-dir as given, then ran `cd "$SCRIPT_DIR"` before using them. A relative project dir like `.` was re-rooted at the scripts directory, so the log and pid redirects failed and the server never reported server-started: "Server failed to start within 5 seconds". Resolve the project dir to an absolute path with `mkdir -p` + `cd && pwd` right before deriving the session paths. mkdir -p keeps the existing behavior of creating a project dir that doesn't exist yet (the Windows lifecycle test relies on it), CDPATH is cleared so a relative name can't resolve to some other directory, and `--` covers names starting with a dash. Works on bash 3.2 without realpath or readlink -f. Fixes #2524. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
3735a50d5a |
fix(sdd): task-brief refuses a brief an unclosed code fence would run to EOF
task-brief ignores Task headings inside fenced code blocks by toggling a flag on every ``` line. When a plan leaves a fence open (an edit deletes a closing fence), the flag stays set for the rest of the file, every later Task heading is invisible, and the requested task's brief runs to EOF. The script then reported success: #2436 saw a 177-line task come back as a 1159-line brief holding tasks 6 through 10, handed to an implementer as its requirements. The awk now notes whether a Task heading line appears inside the fence that is still open at EOF. If one does while the requested task is being captured, the task's end cannot be found, so task-brief deletes the partial output and exits 4, naming the line where the fence opened. If the open fence hides the requested heading itself, it names the fence before the existing not-found error (exit 3), and suppresses the "use the English word Task" hint, which would otherwise blame the plan's English headings for what the fence did. A fence left open that hides no Task heading changes nothing about the brief, so it is still written, with a warning on stderr. Real plans do this: in a corpus of 1,288 plans, refusing on any fence left open at EOF blocked three correct briefs in two plans, each ending in a stray ``` that hides no task. With this rule every brief in that corpus matches dev's. An unclosed fence in a later task leaves an earlier task's brief alone. The plan path reaches awk through the environment rather than -v, which would interpret the backslashes of a Windows path as escapes. The fence rule itself is unchanged, so this composes with #2304's CommonMark fence tracking: a correct parser still cannot close a fence the author never closed. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
750ba92008 |
fix(sdd): task-brief says when a plan's task headings are not in English
task-brief recognizes only the English word `Task` in a task heading. writing-plans' template shows `### Task N:` but never says the word is machine-read, so a model writing a plan in Spanish writes `## Tarea 1:`. task-brief and task-start then report "task 1 not found in plan-es.md (no heading matching 'Task 1')", which reads as "this plan has no task 1" and sends the controller looking for a task that is on line 3 (#2496). When a plan has no Task headings at all, task-brief now prints, before the existing not-found line, that task headings must use the English word "Task" whatever the plan's language, and lists up to five headings shaped like tasks (`<word> <id-with-a-digit>`). A plan that has Task headings, just not the requested one, still gets only the not-found line, so asking for Task 9 of an eight-task plan stays quiet. This deliberately does not accept other words. Plans commonly carry `Phase 1`, `Chunk 2` and `Step 1` headings, and a word-agnostic rule would turn them into tasks. Keeping the word fixed in the plans themselves is a writing-plans wording change, which needs evals. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
f75c01fd9b |
fix(sdd): task-brief recognizes alphanumeric task IDs and matches them whole
task-brief only treated `Task` followed by digits as a task heading, and found the requested task by splicing TASK_NUMBER into a regex followed by `([^0-9]|$)`. Plans that number tasks by lane (`### Task A1`, `### Task B2`) could not be extracted at all: `task-brief plan.md A1` exits 3 "task A1 not found" (#2459). Among 1,288 distinct plans in Jesse's own repositories, 19 plans have such headings (262 headings, IDs like A1, M3a, F.2, W0), and none of those tasks could be briefed. The same splice made the match a prefix match: Task 6 also took a sibling Task 6b (#2175), Task 1 took Task 1.1 and 1.2, Task 2.1 took Task 201 because `.` is any character, and an ID like `6(` crashed awk (#2405). A task heading is now `Task` followed by an ID made of letters and digits, optionally dot-separated, that contains at least one digit. The digit is what keeps `## Task Overview` or `#### Task notes` from becoming a task boundary. awk extracts the heading's ID and compares it to TASK_NUMBER as a whole string, so TASK_NUMBER never reaches awk as a regex. A deeper Task heading whose ID extends the requested one with a letter or dot is a sub-task and stays in the parent's brief, as the prefix match happened to do before: plans in that corpus nest `#### Task 1a` under `### Task 1`, and a Task 1 brief without its sub-tasks would lose most of its requirements. A sub-task's own brief ends at its next sibling. Depth alone is not the test, because plans also drift from `## Task 1` to `### Task 2`, and those are siblings. The heading word stays the English literal `Task`, which is what writing-plans' template uses. Widening it to any word would turn the `Phase 1`, `Chunk 2` and `Step 1` headings that plans commonly carry (308, 182 and 56 of them in the same corpus) into tasks. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
402cfdeed9 |
docs(sdd): say "by its absolute path" at every helper invocation, and test it
The SKILL.md change left skill-relative helper calls elsewhere under skills/: final-review.md (the final whole-branch review package and its re-review), fix-loop.md (the scoped re-review), the reviewer prompt templates' placeholder descriptions, and executing-plans' task-start and task-done. Each now carries the same qualifier: run the script by its absolute path, from the working tree you're executing in. Nothing else in those files changes. tests/sdd-helper-paths/test-sdd-helper-paths.sh is a structural test that fails when any skills/ markdown names a helper (sdd-workspace, task-brief, review-package, task-start, task-done) by a relative scripts/ path without "by its absolute path" within the next few lines. It failed on 8 references before this change and passes on all 14 after. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
74500c1deb |
docs(sdd): run every SDD helper by absolute path from the working tree
Following the code change that makes the helpers act only on the current directory's working tree, give SDD's other skill-relative `bash scripts/<helper>` invocations (sdd-workspace, task-brief, the final-review review-package, and the DONE step's review-package) the same short qualifier executing-plans now uses: run it by its absolute path, from the working tree you're executing in. In the cwd eval the one agent that cd'd into the skill directory did it first at the sdd-workspace line, which never said "from this skill's directory". Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
6ab1c795ae |
docs(sdd): stop pointing script invocations at the skill directory
SDD's DONE step said to run review-package "from this skill's directory", and executing-plans named the scripts by ../subagent-driven-development paths relative to its own skill directory. The scripts act on the git repository of the current directory, like git, so an agent that cd's into the skill directory moves them off the working tree it is executing in: in 6.3 that silently wrote SDD state into the plugin cache; now they fall back to the plan's repository or stop with the no-repo error. Drop "from this skill's directory" and say to run executing-plans' two cross-skill scripts by absolute path from the working tree being executed in. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
8b0eefc87b |
fix(sdd): append git's own error line to the no-repo message
sdd-repo ran git with stderr discarded, so every git failure became "must run from inside the git working tree ... run 'git init'". Where git refuses a working tree the caller is actually inside (dubious ownership on another owner's, FAT, network or WSL /mnt/c checkout; git missing from PATH; the cwd inside .git), that message is false, points at git init in an existing project, and hides the one line naming the real fix. dev printed git's fatal, so this was a diagnostic regression. The shared message stays, and git's first stderr line from whichever check failed now always follows it as "git said: <line>", with no per-case branches: SDD scripts must run from inside the git working tree ... then rerun. git said: fatal: detected dubious ownership in repository at '/r' Tests: every no-repo assertion now requires the second line (a plain non-repo dir gives "git said: fatal: not a git repository"), and a new test simulates dubious ownership with git's GIT_TEST_ASSUME_DIFFERENT_OWNER knob (no root or second uid needed; it skips if the installed git ignores the knob). Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
0d61007ef6 |
fix(sdd): act on the cwd's working tree only, drop the plan-repo fallback
sdd-repo fell back to the plan file's repository when the current directory was outside any repository. That made the plugin-cache case silently succeed somewhere: an agent that cd'd into the skill directory and passed an absolute plan path got whichever checkout that path pointed into. With the plan in the main checkout (where writing-plans leaves it) and execution in a linked worktree, that is the #2429 wrong-worktree bug again, with exit 0. A real session (sdd-cwd-eval sdd-A-5) took exactly this path and only landed in the right place because its plan path happened to be the worktree's. The SDD and executing-plans helpers now pick their repository the way git does: the current directory's working tree, or DIR when given -C DIR. Outside any working tree, sdd-workspace, task-brief, review-package, task-start and task-done all stop with the shared message and write nothing, even when the plan's absolute path is inside a repository. sdd-repo no longer takes PLAN_FILE, since the plan has no say. The two "outside any repository ... uses the plan's repository" tests and the task-start/task-done fallback tests become assertions that the shared message comes out and nothing is written, in the cwd or the plan's repository. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
de67241e0a |
fix(sdd): one no-repo message that puts "run from your working tree" first
sdd-repo's no-repository message told every caller to run 'git init'. That is the right fix for a new project, but the other way to reach it is standing in the wrong directory, such as the plugin's own skill directory after reading "from this skill's directory" literally. There, 'git init' would turn the plugin cache into a repository and hide the real mistake. task-start and task-done were worse. They still read HEAD and BASE in the bare cwd while the brief and ledger went through sdd-repo. From a non-repo cwd with the plan in a repo that has commits, task-start wrote the brief into the plan's repo, then printed git's fatal plus "HEAD has no commit yet ... make an initial commit first" and exited 2. task-done printed git's fatal. review-package in a repo with no commit said "bad BASE: HEAD~1". Every helper that can hit this (sdd-workspace, task-brief, review-package, task-start, task-done) now stops with the same message from sdd-repo, naming the current directory and offering init-and-commit only as the new-project case: SDD scripts must run from inside the git working tree you're executing in, with at least one commit (current directory: <PWD>). If this is a new project, run 'git init' and make a first commit, then rerun. sdd-repo gains --with-commit, which also refuses a repository whose HEAD has no commit. review-package, task-start and task-done pass it because they need HEAD as a BASE or a review range; sdd-workspace and task-brief do not, so a brief can still be written right after git init. task-start and task-done now read HEAD and BASE with git -C in the repository sdd-repo names. Resolution is otherwise unchanged: the cwd's repo, else the plan's, else exit 2. sdd-repo is now executable like its siblings. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
614d80c29a |
fix(sdd): pick the scripts' repository deliberately, add -C DIR, explain a missing repo
The SDD helpers found their repository with a bare `git rev-parse --show-toplevel` in the caller's cwd, and review-package ran every git command there too. Three reports trace back to that one line: - #2429: outside any repository (the skill's own directory in a 7.0 package has no .git), sdd-workspace fed `cd` an empty path. bash 5.2 treats that as a no-op and wrote the workspace into the cwd after printing git's bare fatal; Git Bash failed with "cd: null directory". A controller working on worktree B from worktree A had no way to name B. - #1799: the only way to aim review-package at a worktree was a `cd <worktree> ; review-package ...` compound, which harnesses cannot allowlist because the path and BASE change on every run. - #2242: in a greenfield directory with no repository, task-brief and sdd-workspace printed git's fatal and then carried on in the cwd (or crashed, depending on bash), review-package said "bad BASE: HEAD~1", and task-start printed an empty BASE with exit 0. A new sdd-repo helper is the single place that picks the repository: the cwd's working tree (or -C DIR's), exactly as git does. Anywhere else it stops with exit 2 and one shared message. sdd-workspace and review-package both use it, so they cannot disagree. The cwd still wins over the plan's location on purpose: writing-plans leaves the plan uncommitted in the main checkout, so an executor working in a linked worktree passes the main checkout's plan path, and its workspace and commits belong to the worktree. Resolving from PLAN_FILE first (draft #2439) breaks exactly that flow: review-package then diffs the main checkout and fails with "empty commit range". sdd-workspace, task-brief and review-package take an optional leading `-C DIR` that runs them as if started in DIR, as git -C does, so a caller can name another worktree in one allowlistable command. Each script resolves its own directory before the cd, so the documented `bash scripts/review-package` form from the skill directory keeps working with -C. PR #1809's version cd's first and then fails to find sdd-workspace (exit 127) in that form. task-start now refuses (exit 2) to print a BASE when HEAD has no commit, instead of printing "base: HEAD" or "base: " with exit 0. Co-authored-by: citizen204 <citizen204@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
bb3a5aa594 |
fix(sdd): print a Windows-readable workspace path (#2307)
On Windows, sdd-workspace printed the workspace in MSYS form (/c/Users/... or /tmp/...). Every helper path derives from that line: task-brief's "wrote", review-package's diff path, executing-plans' task-start "brief:". PowerShell resolves /c/Users/x as C:\c\Users\x, so Test-Path and Get-Content on any of them failed. That is the shell an agent gets from Claude Code's PowerShell tool and from Copilot CLI on Windows. Reproduced on Windows 11 from PowerShell and from Claude Code 2.1.308's PowerShell tool. When cygpath is present (Git Bash, MSYS2, Cygwin), print the path through `cygpath -m`, which gives C:/Users/.... PowerShell, cmd and Claude Code's Read tool all accept that form, and so does bash, so the sibling scripts that build file names on top of it keep working. Elsewhere the output is unchanged. Only the printed line changes. The plan-path markers keep pwd -P's spelling, so workspaces created before this change, including absolute markers for out-of-repo plans, still match their plans. PR #2369 converted root and the plan path too, which would rewrite those absolute markers and orphan existing workspaces for out-of-repo plans. Tests: physical_path in both suites now spells paths the way the scripts print them, and test-sdd-workspace adds a check that PowerShell can open the printed workspace and brief paths. That check runs on Windows and is a no-op elsewhere. On Windows the suites failed 10 and 1 assertions before the fix, and both pass after. Co-authored-by: hzxxxx <hhuihihiux@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
5802204a18 |
fix(pi): inject the bootstrap on every prompt, not just the first (#2083)
The pi extension cleared injectBootstrap on agent_end, assuming it marked the end of a session. pi emits agent_end at the end of every agent run, which is once per user prompt, so from the second prompt on no provider request carried the using-superpowers bootstrap. The messages a context handler returns are sent to the provider but are not written to session history, so the bootstrap is never in event.messages on a later call and the existing marker check cannot see an earlier injection. The bootstrap therefore has to be injected into every provider request. Removing the agent_end disarm does exactly that, one copy per request at a stable position at the start of the messages. Observed against pi 0.85.1 with a local stub OpenAI-compatible provider, one session of three prompts (the second makes a tool call): before, only request 1 of 4 carried the bootstrap; after, all 4 carry exactly one copy. The test that asserted the disarm as intended behaviour is replaced by one that drives pi's per-prompt lifecycle events across several prompts and provider requests. The porting guide described the agent_end reset as the pattern to copy and now describes the failure instead. Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
9e663a0dd8 |
fix(opencode): don't mistake a prompt that mentions EXTREMELY_IMPORTANT for the bootstrap
Both bootstrap injectors skip a first user message whose text parts include the substring 'EXTREMELY_IMPORTANT', to avoid injecting twice into the same message. Any user prompt that names the tag matches too, so the bootstrap is silently dropped for that session. That is what #2197 hit. The reporter's probe was opencode run "Is there an 'EXTREMELY_IMPORTANT' block in your context? ..." and the prompt itself tripped the guard. `opencode run` is not the cause: with the real hosts (V1 1.18.21 path and git-package forms, V1 1.19.4, V2 2.1.2, V2 2.1.3) and a request-recording stub model, the reporter's prompt reaches the model without the bootstrap on every host, and a neutral prompt gets the bootstrap on every host. Match the bootstrap's own opening line at the start of a part instead. The injected part always starts with it (the template now uses the same constant), so the double-injection guard keeps working, and a prompt that only mentions the tag no longer suppresses the bootstrap. Fixes #2197 Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
80b085cfb3 |
fix(opencode): inject the V2 bootstrap on compaction and generate requests
The V2 plugin registered its bootstrap injector only on
ctx.session.hook('context'). OpenCode 2 prepares each model request kind
through its own hook: normal agent turns through `context`, the
compaction (summary) request through `compaction`, and session-scoped
one-shot generation through `generate`
(packages/core/src/session/model-request.ts). Every built-in V2 plugin
registers its handler on all three, and the upstream V1 migration guide
says to do the same when a transform must apply to every request kind.
So the compaction request's first user message lacked the bootstrap
that every prior turn carried, and the prompt diverged right after
system + tools. On a provider with prefix caching that is a cold
re-prefill of the whole session on its largest request (#2391).
Reproduced on real OpenCode 2.1.2 and 2.1.3 with a scripted stub model
that pushes the session over the compaction ceiling: before, the
compaction request shares 26.5k of 30.8k serialized chars with the
previous agent request and differs at the first user message; after,
the previous request is a full prefix of the compaction request.
The handler body is unchanged (child-session skip, idempotence guard,
checkpoint-only append), lifted into a named function and registered on
all three hooks, each in its own try/catch. Based on PR #2409.
Fixes #2391
Co-authored-by: Aashish <145881415+aashish254@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba
|
||
|
|
b58deb3b94
|
Merge pull request #2598 from obra/fix/2394-pi-skill-filters
fix(pi): stop resources_discover from bypassing package skill filters |
||
|
|
7e2e91942b
|
Merge pull request #2594 from obra/fix/2503-run-hook-no-bash
fix(hooks): fall back to zsh, or exit quietly, when bash is missing on Unix (#2503) |
||
|
|
4a2a185a37
|
Merge pull request #2593 from obra/fix/2081-session-start-forks
fix(hooks): start no child processes in the SessionStart hook (#2081) |
||
|
|
2c49364a83
|
Merge pull request #2592 from obra/fix/2189-copilot-powershell-hook
fix(hooks): add a powershell form of the SessionStart command for Copilot on Windows (#2189) |
||
|
|
3cbe557575 |
fix(hooks): fall back to zsh, or exit quietly, when bash is missing on Unix (#2503)
On a Unix system without bash, the harness can't honour shell:"bash" and
runs run-hook.cmd with zsh or sh. $BASH is unset there, so the wrapper's
exec "${BASH:-bash}" fails with "command not found: bash" (zsh) or
"exec: bash: not found" (sh), the hook exits 127, and the bootstrap is
lost on every session start.
Keep $BASH first, so the empty-PATH case from #2310 still works, then look
for bash on PATH, then zsh, which runs session-start unchanged (its output
is byte-identical to bash's, including for a SKILL.md full of backslashes,
quotes, tabs and CRs). With neither shell, exit 0 quietly, as the Windows
half already does.
Reproduced with Claude Code 2.1.308 in an alpine container with zsh and no
bash: the hook exited 127 and no bootstrap reached the model before the
change; after it the hook exits 0 and the bootstrap arrives.
Tests run the wrapper under real zsh and under a non-bash sh with a PATH
that holds only zsh, and under that sh with neither shell. They skip where
zsh is absent or sh is bash (Git Bash, macOS).
Co-authored-by: Twot <twotnguyen@users.noreply.github.com>
Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba
|
||
|
|
328685babd |
fix(hooks): start no child processes in the SessionStart hook (#2081)
On Windows, Git Bash emulates fork(), so every command substitution and pipe costs tens of milliseconds. The SessionStart hook runs on every startup, /clear and compaction, and on dev it forked six times: the $(cd ... && pwd) in run-hook.cmd and twice in session-start, $(escape_for_json ...), and printf | cat. Resolve paths with parameter expansion, read the skill with the read builtin, have escape_for_json assign a variable, and absorb EPIPE with trap '' PIPE plus printf 2>/dev/null || true instead of piping through cat. The cat pipe also turned an early-closed stdout into exit 141 under pipefail; the new emit_json exits 0 there. Measured on Windows 11 (VM, Git Bash 5.2), 21 interleaved runs of run-hook.cmd session-start: median 116 ms before, 46 ms after, against a 25 ms floor for one bash start (the wrapper starts two). Claude Code 2.1.308 logged the hook at 181-421 ms before and 137-146 ms after. Output is byte-identical to dev across all five output shapes, two working directories, normal and empty PATH, direct and through the wrapper (40/40 on Linux), and its sha256 matches on Windows. Tests: the cat-stub case, which asserted the pipe, is replaced by a closed-stdout case, and a new case counts process creations with strace on Linux (5 in session-start and 6 through the wrapper on dev, 0 after). Co-authored-by: willow <willowite@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
8f4b3dbd2f |
fix(opencode): tell the model skill ids are bare names (#2583)
Skills name each other with the Claude Code plugin namespace
(`superpowers:brainstorming`), and the using-superpowers bootstrap that
the OpenCode plugin injects says "Let's build X -> superpowers:brainstorming
first". OpenCode registers superpowers skills under bare ids
(`brainstorming`) on both flavors and its `skill` tool does an exact
lookup, so a model that copies the namespaced form gets
"Unable to load skill superpowers:brainstorming" (V2) or
`Skill "superpowers:brainstorming" not found` (V1) and carries on
without the skill. The OpenCode tool mapping said only "Invoke a skill
-> OpenCode's native skill tool" and never stated the id convention.
Reproduced on real hosts (OpenCode 2.1.2 and opencode-ai 1.19.4) with a
scripted stub provider: the namespaced call fails, the bare id loads.
Add the convention to the "Invoke a skill" line of both mappings, with
each flavor's real skill parameter (V1 `name`, V2 `id`), and mirror it
in docs/README.opencode.md. Skill prose keeps the prefix, which is
correct on Claude Code; the translation belongs in the harness mapping,
the same way the Hermes reference shows bare `skill_view("brainstorming")`.
Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba
|
||
|
|
0a4d60db4f |
fix(hooks): add a powershell form of the SessionStart command for Copilot on Windows (#2189)
GitHub Copilot on Windows (Copilot CLI and VS Code Copilot) runs a hook's command through PowerShell and ignores shell:"bash". PowerShell parses "<root>/hooks/run-hook.cmd" session-start as a string expression followed by a bareword, fails with "Unexpected token 'session-start'", and the using-superpowers bootstrap never reaches the session. Copilot prefers a hook's powershell key over command when it is present, so add one that runs the same wrapper with the & call operator. Claude Code ignores the key and keeps dispatching command through Git Bash. Verified on Windows 11 in a VM: Copilot CLI 1.0.103 logged the ParserError and sent no bootstrap before the change, and ran the hook and sent the bootstrap after it. Claude Code 2.1.308 ran the hook and sent the bootstrap both before and after. The new test in test-run-hook-cmd-windows.sh runs the hooks.json powershell value through powershell.exe against a plugin root with a space in its path. Co-authored-by: Tugrul Guner <tugrulguner@users.noreply.github.com> Co-authored-by: Serge ARADJ <orty@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
76b0f89dec |
fix(hermes): skip the controller bootstrap for delegate_task children (#2536)
pre_llm_call returned the using-superpowers bootstrap whenever is_first_turn was true. Hermes computes is_first_turn from an empty conversation history, and a delegate_task child always starts empty, so every child's first turn got the same 5.7k-char controller bootstrap as the parent and had to rely on <SUBAGENT-STOP> to ignore it. Live Hermes delegations on #2536 show children opening with skill_view / read_file on Superpowers skills instead of their assigned work. Hermes builds delegate_task children with platform="subagent" (tools/delegate_tool.py) and forwards that as the hook's platform argument, so gate injection on it. parent_session_id is not a safe signal: Hermes also sets it on the continuation session it creates on context compression. Verified against a real Hermes install (hermes-agent 484de065) by running its plugin discovery and agent.turn_context._collect_pre_llm_call_context for a parent and a subagent first turn: 5757/5757 chars before, 5757/0 after. Co-authored-by: Twot <twotnguyen@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |
||
|
|
7455441f77 |
fix(pi): stop resources_discover from bypassing package skill filters
The pi extension registered a resources_discover handler that returned the whole skills/ directory. pi applies a package's `skills` filter (the one `pi config` writes) only to manifest-declared resources; paths an extension contributes are merged afterwards, unfiltered. So with `"skills": []` or an allowlist on the superpowers package entry, pi 0.85.1 still loaded all 15 skills, every one attributed to extension:superpowers. package.json already declares `pi.skills: ["./skills"]`, and pi loads that with the user's filter applied, so the handler was redundant for package installs, including the README's `pi -e /path/to/superpowers`. Remove it. The bootstrap handlers are unchanged. The porting guide now names the manifest as pi's discovery mechanism. Verified against the real pi 0.85.1 CLI (RPC get_commands, no model call): skills [] loads 0 (was 15), an allowlist of using-superpowers loads 1 (was 15), no filter loads 15, `pi -e <checkout>` loads 15. Fixes #2394 Co-authored-by: m2dumpling <224757904+m2dumpling@users.noreply.github.com> Claude-Session: https://claude.ai/code/session_01SHANcr4A71nzuU9et4Fnba |