@oisin-ee/pi-dogsled 0.13.0 → 0.13.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -188,7 +188,7 @@ A reader claims records with `inbox claim`, which is a lease. A claimed record i
188
188
  Readers:
189
189
 
190
190
  - **Pi:** the extension watches its inbox file, injects each batch as one `dogsled` message (`steer` while the agent runs, a new turn when it is idle), and acknowledges it when Pi has written the message to the session.
191
- - **Claude Code and Codex:** `dogsled hook inbox --harness claude|codex --event Stop|UserPromptSubmit`, registered by the plugin. The first hook run registers the reader. At `Stop`, records continue the turn as `{"decision":"block","reason":…}`; at `UserPromptSubmit`, they go beside the user's text as `additionalContext`. Records printed are acknowledged. An empty inbox prints nothing, so a stop ends as usual.
191
+ - **Claude Code and Codex:** `dogsled hook inbox --harness claude|codex --event Stop|UserPromptSubmit`, registered by the plugin. The first hook run registers the reader. At `Stop`, records continue the turn as `{"decision":"block","reason":…}`; at `UserPromptSubmit`, they go beside the user's text as `additionalContext`. Records printed are acknowledged. At `Stop`, the same response also includes a new reminder about finished children with work to land. It prints nothing when neither is pending.
192
192
 
193
193
  A hook runs only when its harness acts, so an idle Claude Code or Codex agent sees a record at its next prompt or stop. Pi has no such delay.
194
194
 
@@ -446,12 +446,26 @@ The removed lead ledger and event log are not read or migrated.
446
446
 
447
447
  ## Prompt context and integrations
448
448
 
449
- `dogsled hook context --harness claude|codex|pi` formats the same text as `status --brief`.
449
+ `dogsled hook context --harness claude|codex|pi` leads with your own children and jobs, then shows the fleet totals from `status --brief`.
450
+ The owner summary separates work to land, attention, idle, done, running, and queued work.
451
+ The `To land:` line names finished children with unmerged commits or uncommitted changes.
450
452
  Claude Code and Codex register `SessionStart` and `UserPromptSubmit` context hooks, and `UserPromptSubmit` and `Stop` inbox hooks (see [Inbox](#inbox)), in `plugins/dogsled`.
451
453
  Each registration supplies `--event`. The default context event is `UserPromptSubmit`.
452
454
  The CLI never reads stdin. Claude Code and Codex receive `hookSpecificOutput` JSON with `hookEventName` and `additionalContext`.
453
455
  Pi receives plain text through its `before_agent_start` extension. All three use the same snapshot reader and formatter.
454
456
 
457
+ Before an orchestrator stops, the stop gate checks its own TO LAND children.
458
+ Pi calls `dogsled hook gate` from `agent_before_settle` and adds a visible message that continues the run.
459
+ Claude Code and Codex include the reminder in their existing `Stop` inbox response.
460
+ The reminder requests a review, a commit from dirty children, integration, or an explicit blocker or deferral.
461
+ It never commits, merges, closes, or discards work itself. Clean readers and working children do not trigger it.
462
+
463
+ The gate records each set of child item IDs, commit counts, and dirty states in `gate.json`.
464
+ It continues once per distinct set, across process restarts. Row order and idle/done transitions do not cause another reminder.
465
+ New states can trigger another reminder. Closing all owner items clears the history.
466
+ Pi skips the gate on errors, aborts, and boundaries that already request continuation.
467
+ This is a bounded reminder, not a permanent prohibition on stopping.
468
+
455
469
  Without `HERDR_ENV`, service snapshots, or a usable binary, the hooks add nothing.
456
470
  A hook has a five-second command budget. Hook failures exit successfully without output.
457
471
  Plugin commands end with `|| true`. Pi also leaves the prompt unchanged if the binary fails.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oisin-ee/pi-dogsled",
3
- "version": "0.13.0",
3
+ "version": "0.13.1",
4
4
  "description": "Pi extension for dogsled: the board, the /dogsled panel, the inbox reader, and the dogsled tools. Needs the dogsled binary of the same version.",
5
5
  "type": "module",
6
6
  "license": "MIT",
package/pi/index.ts CHANGED
@@ -240,12 +240,23 @@ export default function dogsled(pi: ExtensionAPI) {
240
240
  // A delivered message is in the transcript once Pi ends it: only then is it acknowledged.
241
241
  pi.on("message_end", async event => { await inbox.ended(event.message); });
242
242
  pi.on("agent_settled", () => { inbox.settled(); });
243
+ pi.on("agent_before_settle", async event => {
244
+ if (!owner || event.outcome !== "completed" || !event.context.canContinue || event.continue) return;
245
+ // The Rust gate owns selection and durable deduplication across all harnesses.
246
+ const result = await pi.exec(binary, ["hook", "gate"], { timeout: 6_000 });
247
+ if (result.code !== 0) throw new Error(`dogsled stop gate failed: ${result.stderr.trim() || `exit ${result.code}`}`);
248
+ if (!result.stdout.trim()) return;
249
+ return {
250
+ entries: [...event.entries, { type: "custom_message" as const, customType: MESSAGE_TYPE, content: result.stdout.trim(), display: true }],
251
+ continue: true,
252
+ };
253
+ });
243
254
  pi.on("before_agent_start", async (event) => {
244
255
  // Context is optional, including when the binary is absent or fails.
245
256
  try {
246
257
  const result = await pi.exec(binary, ["hook", "context", "--harness", "pi"], { timeout: 6_000 });
247
258
  if (result.code !== 0 || !result.stdout.trim()) return;
248
- return { systemPrompt: `${event.systemPrompt}\n\n## Host status\n${result.stdout.trim()}\n` };
259
+ return { systemPrompt: `${event.systemPrompt}\n\n## Your work and fleet status\n${result.stdout.trim()}\n` };
249
260
  } catch {
250
261
  return;
251
262
  }
@@ -18,7 +18,10 @@ dogsled read NAME_OR_PANE [--host H]
18
18
  ```
19
19
 
20
20
  The board groups what you started by what you must do: TO LAND (a finished child with commits), ATTENTION (blocked, stalled, failed), RUNNING, and WAITING (queued for a host). Each agent row shows its harness and model; each job row its command.
21
- Your prompt context carries host status and a `To land:` line. In Pi, the board widget above the editor shows host meters, the current task, and grouped agents and jobs. Alt+W or `/work` expands it in place. Work inspection stays inline, not in a popup. Todos follow the Pi branch; agents and jobs follow the owner pane. `/dogsled` retains host, profile, and inbox administration.
21
+ Your prompt context leads with your own children and jobs, then a `To land:` line, then fleet status.
22
+ Before you stop, a gate reminds you once per distinct set of finished children with unmerged commits or uncommitted changes.
23
+ Read each result. Ask dirty children to finish and commit. Integrate approved work, or report its blocker or deferral.
24
+ Never discard dirty work to satisfy the reminder. The gate does not close or merge anything. In Pi, the board widget above the editor shows host meters, the current task, and grouped agents and jobs. Alt+W or `/work` expands it in place. Work inspection stays inline, not in a popup. Todos follow the Pi branch; agents and jobs follow the owner pane. `/dogsled` retains host, profile, and inbox administration.
22
25
 
23
26
  ## Delegate
24
27