Skip to content

sync(plugin): retime the mid-session offer and make declining recoverable (v1.17.0) - #32

Open
darrenzhu wants to merge 1 commit into
mainfrom
sync/plugin-v1.17.0
Open

sync(plugin): retime the mid-session offer and make declining recoverable (v1.17.0)#32
darrenzhu wants to merge 1 commit into
mainfrom
sync/plugin-v1.17.0

Conversation

@darrenzhu

Copy link
Copy Markdown
Contributor

Syncs plugin/ from forge-mcp at 3eeeae60 (branch claude/shi-905-implementation-plan-a2377d). v1.16.0 → v1.17.0.

What changed for users

The mid-session tracking offer used to become eligible at the end of the very first turn, before anything was known about the session — so it read as onboarding noise. And dismissal was terminal, so one reflexive decline disabled tracking for the rest of the session, including at the moment it would actually have helped. Those were one failure mode, not two.

  • The offer waits for real signal — 4 turns, 5 minutes of active work, or a commit. Where the session log can't be read it degrades to turns only, never wall-clock: three idle hours with one turn is not signal.
  • Declining is graded. "Not now" returns later and the returning offer acknowledges the earlier decline instead of repeating itself; only an explicit opt-out is terminal.
  • The offer says why it's appearing now, quoting the figures that opened the gate, in prose — "going for 1 turn", not "1 turns".

Files

Five hooks, one of them new:

File Note
git-head.cjs New. The git-milestone read, extracted into its own module
prompt-router.cjs Seeds the commit baseline on the first prompt
session-state.cjs New session-state fields
stop-observer.cjs Eligibility gate; shrinks as the git logic moves out
workflow-tracker.cjs Soft-decline outcome mapping

git-head.cjs is a required module (require('./git-head.cjs')), not an event hook — no hooks.json wiring needed.

The worktree case

The milestone read follows the gitdir: pointer rather than reading .git/HEAD. Inside a worktree .git is a file, and the main checkout's HEAD names a different branch — so a naive read returns the wrong branch, not no branch. It also walks up from subdirectories to the enclosing checkout, and stops at the home directory so a dotfiles repo is never adopted as the project.

What was deliberately not touched

token-usage.cjs, workflow-guard.cjs, hooks.json and the SKILL.md files carry per-platform localizations and are unchanged. Only the five hooks above and the version were synced.

Where a synced hook had comment-only drift from the canonical source (reflows and near-synonyms — no functional difference), it was normalized to source. Diffs were checked against git diff --numstat to confirm every change is proportional and no line endings flipped.

Verification

Source suite green before syncing: 8072 pass, 0 fail. Each target's modules load clean.

Source PR: ShipToday/forge-mcp#991 — not yet merged. This sync is built on that branch.

🤖 Generated with Claude Code

…able (v1.17.0)

Propagates forge-mcp's plugin/ at 3eeeae60. Five hooks, one of them new.

The mid-session tracking offer used to become eligible at the end of the
very first turn, before anything was known about the session, so it read as
onboarding noise — and dismissal was terminal, which meant one reflexive
decline disabled tracking for the rest of the session, including at the
moment it would have helped. Those were one failure, not two.

- The offer now waits for real signal: 4 turns, 5 minutes of active work,
  or a commit. Where the session log cannot be read it degrades to turns
  only, never wall-clock.
- Declining is graded. "Not now" comes back later and the returning offer
  acknowledges the earlier decline; only an explicit opt-out is terminal.
- The git-milestone read moves into its own module, hooks/git-head.cjs. It
  follows the gitdir: pointer so worktrees resolve to their own HEAD rather
  than the main checkout's, walks up from subdirectories to the enclosing
  checkout, and stops at the home directory so a dotfiles repo is never
  mistaken for the project.
- The baseline is seeded on the first prompt, so a commit made during the
  first turn counts instead of becoming its own baseline.
- The offer's copy reads as prose — "going for 1 turn", not "1 turns".

Source verified green before syncing: 8072 tests pass, 0 fail.

Localized files were left alone: token-usage.cjs, workflow-guard.cjs,
hooks.json and the SKILL.md files are untouched in every target.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant