@openlines/opl-pi-sht 0.2.2 → 0.2.4

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
@@ -14,6 +14,14 @@
14
14
 
15
15
  A portable collection of various Pi coding agent extensions. Repository directories and config files use `opl-`; established Pi-facing commands and tool names stay compatible.
16
16
 
17
+ <div align="center">
18
+
19
+ >
20
+ > ## v0.2.4 (22 Sept 2026) - Pi 0.87 host-loader smoke test now runs in CI<br/>see [CHANGELOG.md](CHANGELOG.md) for more details.
21
+ >
22
+
23
+ </div>
24
+
17
25
  ## Installation
18
26
 
19
27
  ### Pi package
@@ -105,7 +113,7 @@ Cold prompt-cache write, measured /init session (opl-modes lazy tools + MCP adap
105
113
 
106
114
  ### Run the agent without babysitting it
107
115
 
108
- - **`opl-modes`** chat and plan modes swap the active toolset for read-only lists and gate Bash to safe inspection patterns **per shell segment**, so `cat f && node -e '...'`, `cat x & rm -rf /tmp/x`, and `echo "$(node -e ...)"` can no longer ride the first command's allowance. Destructive checks still fire inside otherwise-safe commands (anchored to command position, so `du -sh` and `find . -name '*.sh'` stay allowed; `find -delete`, `find -fprint`, `git log --output`, `sort -o`, `npm audit fix`, `git clean`, `sudo`, and quote-obfuscated `r"m"`/`-del"ete"` are blocked; `env`/`printenv` are not safe-listed). The plan to execute lifecycle keeps exploration and mutation cleanly separated. Add custom modes (like below) for your workflow needs.
116
+ - **`opl-modes`** chat and plan modes swap the active toolset for read-only lists and gate Bash to safe inspection patterns **per shell segment**, so `cat f && node -e '...'`, `cat x & rm -rf /tmp/x`, and `echo "$(node -e ...)"` can no longer ride the first command's allowance. Destructive checks still fire inside otherwise-safe commands (anchored to command position, so `du -sh` and `find . -name '*.sh'` stay allowed; `find -delete`, `find -fprint`, `git log --output`, `sort -o`, `npm audit fix`, `git clean`, `sudo`, and quote-obfuscated `r"m"`/`-del"ete"` are blocked; `env`/`printenv` are not safe-listed). The plan to execute lifecycle keeps exploration and mutation cleanly separated. Add custom modes (like below) for your workflow needs. Execute-mode auto-exit needs pi >= 0.87.0 (the `agent_before_settle` boundary).
109
117
  ![custom mode sample](images/ss-mode-custom.png)
110
118
  - `load_tools` activation is bounded by the current mode, so a read-only mode cannot be tricked into enabling a write-capable tool.
111
119
  - **`opl-guardian`** stops a malformed provider tool-call record from poisoning the session: it removes calls missing an ID or name before Pi persists or replays them, while preserving dropped records in `err/guardian.jsonl` for an upstream report.
@@ -221,4 +229,4 @@ A Pi package (npm or Git) still needs the one-time `npx playwright install chrom
221
229
  npm test
222
230
  ```
223
231
 
224
- Run one extension suite with `npm run test:opl-<name>` for `browser`, `footer`, `guardian`, `init`, `input`, `modes`, `questionnaire`, `todo`, `webaccess`, `simplebench`, or `ctxtrim`. Every helper, functional, and selected-entrypoint smoke check uses Bun's named-test reporter; output includes per-test status, timings, and pass/fail totals. Functional tests cover deterministic helpers where practical; smoke tests bundle entrypoints and parse config. They do not test live TUI behavior, provider credentials, network access, or PDF extraction.
232
+ Run one extension suite with `npm run test:opl-<name>` for `browser`, `footer`, `guardian`, `init`, `input`, `modes`, `questionnaire`, `todo`, `webaccess`, `simplebench`, or `ctxtrim`. `npm run test:pi-host` uses Pi 0.87.0's real extension loader to load every entrypoint and assert no loader errors. Every helper, functional, and selected-entrypoint smoke check uses Bun's named-test reporter; output includes per-test status, timings, and pass/fail totals. Functional tests cover deterministic helpers where practical; smoke tests bundle entrypoints and parse config. They do not test live TUI behavior, provider credentials, network access, or PDF extraction.
@@ -11,7 +11,7 @@ Unified mode manager for Pi. It provides normal, read-only chat, read-only plann
11
11
  - `--chat` and `--plan` start Pi in the corresponding read-only mode.
12
12
  - The configured cycle shortcut rotates through enabled visible modes. Execute mode is excluded from cycling because it requires an active plan. The default `shift+tab` is also Pi's built-in `app.thinking.cycle`, so both fire on one press; rebind either action in `~/.pi/agent/keybindings.json` (or pick another `shortcuts.cycleMode`) if you want them separate.
13
13
 
14
- Plans are Markdown files under `.pi/plans/` with the `plan-` filename prefix. A plan name must contain at least one letter or digit, so `/plan .` or `/plan --` is rejected instead of producing an untitled `plan-.md`. `plan_complete` is available in execute mode and in any mode that sets `allowPlanComplete`. On completion, the plan file is deleted when `cleanup.cleanupOnComplete` is enabled. If execution ends without `plan_complete`, execute mode is exited automatically — but only when a turn actually finished: an aborted (ESC) or errored turn keeps execute mode active so the plan can be resumed.
14
+ Plans are Markdown files under `.pi/plans/` with the `plan-` filename prefix. A plan name must contain at least one letter or digit, so `/plan .` or `/plan --` is rejected instead of producing an untitled `plan-.md`. `plan_complete` is available in execute mode and in any mode that sets `allowPlanComplete`. On completion, the plan file is deleted when `cleanup.cleanupOnComplete` is enabled. If execution ends without `plan_complete`, execute mode is exited automatically at Pi's `agent_before_settle` boundary (added in Pi 0.87.0) — but only when the run settled as `completed`: an aborted (ESC) or errored run keeps execute mode active so the plan can be resumed. On Pi < 0.87.0 this auto-exit is unavailable because the boundary is never emitted; `plan_complete` still exits the mode on any version.
15
15
 
16
16
  ## Extension features
17
17
 
@@ -23,6 +23,7 @@ import type {
23
23
  ToolCallEventResult,
24
24
  ToolResultEvent,
25
25
  AgentEndEvent,
26
+ AgentBeforeSettleEvent,
26
27
  } from "@earendil-works/pi-coding-agent";
27
28
  import { DynamicBorder } from "@earendil-works/pi-coding-agent";
28
29
  import type { Model } from "@earendil-works/pi-ai";
@@ -668,26 +669,23 @@ export default function modeSwitcher(pi: ExtensionAPI) {
668
669
  enterOffMode(ctx, "Plan implemented. Plan mode OFF.");
669
670
  });
670
671
 
671
- // ─── Event: agent_end (extract plan text in PLAN mode; auto-exit execute) ───
672
-
673
- pi.on("agent_end", async (event: AgentEndEvent, ctx: ExtensionContext) => {
674
- // If plan_complete was never called, exit execute mode automatically.
675
- // (If it was called, mode is already "off" here — this check is a no-op.)
676
- if (getMode() === "execute") {
677
- // An aborted turn (ESC) is a pause, not a finished execution: stay in execute mode
678
- // so the plan can be resumed instead of silently dropping out mid-plan. Pi emits an
679
- // assistant message with stopReason "aborted" even when the abort lands before the
680
- // first token, so there is always a message to read here.
681
- const lastAssistant = [...event.messages].reverse().find((m) => m.role === "assistant") as
682
- | { stopReason?: string }
683
- | undefined;
684
- // Only a turn that actually finished counts as done: "aborted"/"error" (and a missing
685
- // assistant message) are pauses, so execute mode survives ESC and provider failures.
686
- const reason = lastAssistant?.stopReason;
687
- if (reason && reason !== "aborted" && reason !== "error") enterOffMode(ctx, "Execution complete. Mode OFF.");
688
- return;
672
+ // ─── Event: agent_before_settle (auto-exit execute when the run is truly done) ───
673
+
674
+ // Pi 0.87 boundary: fires after any automatic retry, compaction-and-retry, or queued
675
+ // follow-up work, so execute mode is not dropped mid-plan at an intermediate agent_end.
676
+ pi.on("agent_before_settle", async (event: AgentBeforeSettleEvent, ctx: ExtensionContext) => {
677
+ // If plan_complete was never called, exit execute mode automatically once Pi has fully
678
+ // settled. (If it was called, mode is already "off" here — this check is a no-op.)
679
+ // "aborted" (ESC) and "error" (provider failure) are pauses, not finished executions;
680
+ // only a completed run exits execute mode.
681
+ if (getMode() === "execute" && event.outcome === "completed") {
682
+ enterOffMode(ctx, "Execution complete. Mode OFF.");
689
683
  }
684
+ });
685
+
686
+ // ─── Event: agent_end (extract plan text in PLAN mode) ───
690
687
 
688
+ pi.on("agent_end", async (event: AgentEndEvent, ctx: ExtensionContext) => {
691
689
  if (getMode() !== "plan") return;
692
690
  if (!ctx.hasUI) return;
693
691
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openlines/opl-pi-sht",
3
- "version": "0.2.2",
3
+ "version": "0.2.4",
4
4
  "description": "opl-pi-sht (shouldHaveThat) Pi coding-agent extension kit: token-efficient context, safe modes, fingerprinted /init, model benchmarking, web access, and browser automation.",
5
5
  "repository": {
6
6
  "type": "git",
@@ -40,7 +40,7 @@
40
40
  },
41
41
  "type": "module",
42
42
  "scripts": {
43
- "test": "npm run test:opl-browser && npm run test:opl-footer && npm run test:opl-guardian && npm run test:opl-init && npm run test:opl-input && npm run test:opl-modes && npm run test:opl-questionnaire && npm run test:opl-todo && npm run test:opl-webaccess && npm run test:opl-simplebench && npm run test:opl-ctxtrim",
43
+ "test": "npm run test:opl-browser && npm run test:opl-footer && npm run test:opl-guardian && npm run test:opl-init && npm run test:opl-input && npm run test:opl-modes && npm run test:opl-questionnaire && npm run test:opl-todo && npm run test:opl-webaccess && npm run test:opl-simplebench && npm run test:opl-ctxtrim && npm run test:pi-host",
44
44
  "test:opl-browser": "bun test tests/opl-browser-helpers.test.mjs && OPL_EXTENSION=opl-browser bun test tests/extension-smoke.test.mjs",
45
45
  "test:opl-footer": "bun test tests/opl-footer-helpers.test.mjs && OPL_EXTENSION=opl-footer bun test tests/extension-smoke.test.mjs",
46
46
  "test:opl-guardian": "bun test tests/opl-guardian.test.mjs && OPL_EXTENSION=opl-guardian bun test tests/extension-smoke.test.mjs",
@@ -51,6 +51,10 @@
51
51
  "test:opl-todo": "bun test tests/opl-todo-config.test.mjs tests/opl-todo-render.test.mjs && OPL_EXTENSION=opl-todo bun test tests/extension-smoke.test.mjs",
52
52
  "test:opl-webaccess": "bun test tests/opl-webaccess-helpers.test.mjs && OPL_EXTENSION=opl-webaccess bun test tests/extension-smoke.test.mjs",
53
53
  "test:opl-simplebench": "bun test tests/opl-simplebench.test.ts && OPL_EXTENSION=opl-simplebench bun test tests/extension-smoke.test.mjs",
54
- "test:opl-ctxtrim": "bun test tests/opl-ctxtrim.test.ts && OPL_EXTENSION=opl-ctxtrim bun test tests/extension-smoke.test.mjs"
54
+ "test:opl-ctxtrim": "bun test tests/opl-ctxtrim.test.ts && OPL_EXTENSION=opl-ctxtrim bun test tests/extension-smoke.test.mjs",
55
+ "test:pi-host": "bun test tests/pi-host-loader.test.mjs"
56
+ },
57
+ "devDependencies": {
58
+ "@earendil-works/pi-coding-agent": "0.87.0"
55
59
  }
56
60
  }