Browse Source

fix(skills): Summon recover chip resumes in project root, no worktree re-spawn

The recover-chip wording said "start a fresh session there" and carried the
original worktree path, so the recovering chip spawned a SECOND chip pointing
at the worktree instead of resuming in place — a confusing double-spawn.

Reword the per-card + batch recover actions and the SKILL.md recover
convention: the chip cwd is the project root (worktree suffix stripped), the
chip IS the recovered session (read transcript, distil brief, resume in
place), and it must not spawn a further chip or open the worktree as a
separate session. The worktree path stays reference-only.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
0xDarkMatter 3 weeks ago
parent
commit
1549a68fa4
2 changed files with 3 additions and 3 deletions
  1. 1 1
      skills/summon/SKILL.md
  2. 2 2
      skills/summon/assets/picker-widget.html

+ 1 - 1
skills/summon/SKILL.md

@@ -172,7 +172,7 @@ When summon is invoked from **inside a Claude chat session** (Desktop chat, clau
 1. Run **`summon pick --json --rich`** with a **generous window** (e.g. `--days 30`; add `--cwd`/`--title` filters as asked) and parse the envelope (schema `claude-mods.summon.pick/v2`). `--rich` costs one transcript read per session and adds the per-card display metrics; the widget has its own client-side "last X" age filter (24h/3d/7d/30d/all), so the user narrows in-widget without a CLI re-run.
 2. Render [`assets/picker-widget.html`](assets/picker-widget.html) via the `show_widget` tool: drop the envelope's `data` array straight into the `S` array inside the marked `<script id="D">` block — the widget consumes the pick/v2 **objects verbatim** (keys documented in the template header). Archived sessions are hidden by default (a "show archived" toggle reveals them); cross-account copies dedupe by `sessionId`. Each card shows a **context-usage donut + token count** (last-turn occupancy vs the session's window — 200k or 1M, auto-detected from peak), an **activity-density strip** (24 buckets over the session's lifetime), and chips for model/effort, age, turns, messages, tool calls, on-disk size, and duration, plus **grid/list** and **sort** controls. `firstAsk` is the mechanical opening ask; you MAY replace it with a distilled one-liner by setting a `summary` field on the row before injecting.
 3. Act on the `sendPrompt` callbacks the widget fires. Per-card `↗ summon` and `⟳ recover` (and the footer's "Recover/Summon selected") are worded to be **spawned as background chips** — when one arrives, call `spawn_task` (one chip per session) rather than doing the work inline, so the user's current turn keeps flowing:
-   - **"Recover … spawn it as a background chip"** → `spawn_task` per session: the chip reads the transcript (resolve via `summon recover <id>` / the wrapper→transcript logic), writes a hand-off brief, and starts a fresh seeded session. Set the chip `cwd` to the session's **project root** (not the worktree path).
+   - **"Recover … as a background chip"** → one `spawn_task` per session, with the chip `cwd` set to the session's **project root** (strip any `\.claude\worktrees\<name>` suffix). Word the chip prompt so the chip *is* the recovered session: it reads the original transcript (resolve via `summon recover <id>` / the wrapper→transcript logic), writes a hand-off brief, and **resumes the work in place** in the project folder. The chip must **not** spawn a further chip and must **not** open the original worktree path as a separate session — that path is reference-only, for locating the branch and any in-progress changes. (The failure mode this prevents: a chip prompt that says "start a fresh session there" plus a worktree path makes the recovering chip spawn a *second* chip into the worktree. The chip already **is** the fresh session — tell it to continue, not to spawn.)
    - **"Summon (copy) these…"** → transfer flow: `summon` with `--select` for exactly those sessions, `--dry-run` preview first, then the real run once the user confirms.
    - **"Peek session…"** → `summon --peek <id>`.
 

+ 2 - 2
skills/summon/assets/picker-widget.html

@@ -192,7 +192,7 @@ function render(){
     el.querySelector('.act-peek').addEventListener('click',function(){sendPrompt('Peek session '+s.sessionId+' ("'+s.title+'") — run summon --peek '+s.sessionId+' and show me its last few messages.');});
     el.querySelector('.act-copy').addEventListener('click',function(){var b=this;navigator.clipboard&&navigator.clipboard.writeText(s.sessionId);var i=b.querySelector('i');i.className='ti ti-check';setTimeout(function(){i.className='ti ti-copy';},900);});
     el.querySelector('.act-summon').addEventListener('click',function(){sendPrompt('Summon (copy) the "'+s.title+'" session ('+s.sessionId+') into my other account — show the plan with summon --dry-run first.');});
-    el.querySelector('.act-recover').addEventListener('click',function(){sendPrompt('Recover the "'+s.title+'" session ('+s.sessionId+', '+s.cwd+') via the summon skill'+String.fromCharCode(39)+'s recover process, and spawn it as a background chip: read its transcript, write a concise hand-off summary of where it left off and what'+String.fromCharCode(39)+'s next, then start a fresh session there seeded with that summary.');});
+    el.querySelector('.act-recover').addEventListener('click',function(){sendPrompt('Recover the "'+s.title+'" session ('+s.sessionId+', '+s.cwd+'): spawn ONE background chip whose cwd is the PROJECT ROOT of that path (drop any \\.claude\\worktrees\\... suffix). That chip IS the recovered session — it reads the original transcript, writes a concise hand-off summary, and resumes the work in place in the project folder. It must NOT spawn any further chip and must NOT open the worktree folder as a separate session (the worktree path is reference-only, for locating the branch and in-progress changes).');});
   });
   refreshFoot();
 }
@@ -200,7 +200,7 @@ function render(){
 document.getElementById('bGrid').addEventListener('click',function(){deck.className='deck grid';this.classList.add('on');document.getElementById('bList').classList.remove('on');});
 document.getElementById('bList').addEventListener('click',function(){deck.className='deck list';this.classList.add('on');document.getElementById('bGrid').classList.remove('on');});
 document.getElementById('bClr').addEventListener('click',function(){picked={};render();});
-document.getElementById('bRec').addEventListener('click',function(){var l=DATA.filter(function(s){return picked[s.sessionId];});sendPrompt('Recover these '+l.length+' sessions via the summon skill'+String.fromCharCode(39)+'s recover process — spawn ONE background chip per session (read transcript, distil a hand-off brief, start a fresh seeded session):\n'+fmtList(l));});
+document.getElementById('bRec').addEventListener('click',function(){var l=DATA.filter(function(s){return picked[s.sessionId];});sendPrompt('Recover these '+l.length+' sessions — spawn ONE background chip per session, each with its cwd set to the PROJECT ROOT (drop any \\.claude\\worktrees\\... suffix). Each chip IS its recovered session: read the original transcript, distil a hand-off brief, and resume the work in place in the project folder. No chip may spawn a further chip or open a worktree folder as a separate session:\n'+fmtList(l));});
 document.getElementById('bSum').addEventListener('click',function(){var l=DATA.filter(function(s){return picked[s.sessionId];});sendPrompt('Summon (copy) these '+l.length+' sessions into my other account — run summon --select for exactly these, show the plan with --dry-run first:\n'+fmtList(l));});
 render();
 })();