@juicesharp/rpiv-pi 0.12.4 → 0.12.6

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
@@ -94,6 +94,22 @@ On first Pi Agent session start, rpiv-pi automatically:
94
94
 
95
95
  Each skill produces an artifact consumed by the next. Run them in order, or jump in at any stage if you already have the input artifact.
96
96
 
97
+ ### Recipes
98
+
99
+ Skills compose. Pick the entry point that matches your intent:
100
+
101
+ - **Form context before a task** — `/skill:discover "[topic]"` → `/skill:research <questions artifact>`. Produces a high-signal subspace of the codebase relevant to your topic, ready to feed directly into the next prompt.
102
+ - **Compare approaches before designing** — `/skill:explore "[problem]"` → `/skill:design <solutions artifact>`. Use when multiple valid solutions exist; the solutions artifact is a first-class input to `design` alongside a `research` artifact.
103
+ - **Full feature build** — `/skill:discover` → `research` → `design` → `plan` → `implement` → `validate` → (`code-review` ↔ `commit`). The default pipeline; jump in at any stage if you already have the input artifact. Review and commit are interchangeable in order — review `staged`/`working` before committing, or commit first and review the resulting branch (empty scope, first-parent vs default).
104
+ - **Investigate a bug** — `/skill:discover "why does X fail"` → `/skill:research <questions artifact>`. Fix from the research output without writing a plan when the change is small.
105
+ - **Adjust mid-implementation** — `/skill:revise <plan artifact>` → resume `/skill:implement`. Use when new constraints land after the plan is drafted.
106
+ - **Review before shipping** — `/skill:code-review` ↔ `/skill:commit`. Order is your call: review `staged`/`working` before committing to catch issues at the smallest blast radius, or commit first and review the resulting branch (empty scope defaults to feature-branch-vs-default-branch, first-parent). Produces a Quality/Security/Dependencies artifact under `thoughts/shared/reviews/` with claim-verifier-grounded findings and `status: approved | needs_changes`.
107
+ - **Audit a specific scope** — `/skill:code-review <commit|staged|working|hash|A..B|branch>`. Targeted lenses over a commit, range, staged/working tree, or PR branch; advisor adjudication applies when configured (`/advisor`).
108
+ - **Review-driven plan revision** — `/skill:code-review` → `/skill:revise <plan artifact>` → resume `/skill:implement`. When a mid-stream review surfaces structural findings that the existing plan can't absorb as spot fixes.
109
+ - **Scaffold manual UI test specs** — `/skill:outline-test-cases` → `/skill:write-test-cases <feature>`. Outline first via Frontend-First Discovery to map project scope and avoid duplicate coverage, then generate flow-based manual test cases (with a regression suite) under `.rpiv/test-cases/<feature>/`.
110
+ - **Hand off across sessions** — `/skill:create-handoff` → (new session) `/skill:resume-handoff <doc>`. Preserves context when stopping mid-task.
111
+ - **Onboard a fresh repo** — `/skill:annotate-guidance` once, then use the rest of the pipeline normally. Use `annotate-inline` instead if the project follows the `CLAUDE.md` convention.
112
+
97
113
  ### Skills
98
114
 
99
115
  Invoke via `/skill:<name>` from inside a Pi Agent session.
@@ -157,18 +173,18 @@ Agents are dispatched automatically by skills via the `Agent` tool — you don't
157
173
 
158
174
  | Agent | Purpose |
159
175
  |---|---|
160
- | `claim-verifier` | Grounds reconciled code-review findings at cited `file:line`; tags Verified / Weakened / Falsified |
176
+ | `claim-verifier` | Grounds each supplied code-review claim against repository state and tags it Verified / Weakened / Falsified |
161
177
  | `codebase-analyzer` | Analyzes implementation details for specific components |
162
- | `codebase-locator` | Locates files and components relevant to a task |
163
- | `codebase-pattern-finder` | Finds similar implementations and usage patterns |
164
- | `diff-auditor` | Row-only patch auditor; walks a patch against a caller-supplied surface-list and emits `file:line \| verbatim \| surface-id \| note` rows |
165
- | `integration-scanner` | Maps inbound references, outbound deps, and config wiring |
166
- | `peer-comparator` | Pairwise peer-invariant comparator; tags each peer invariant Mirrored / Missing / Diverged / Intentionally-absent |
167
- | `precedent-locator` | Finds similar past changes in git history |
168
- | `test-case-locator` | Finds existing test cases and reports coverage stats |
169
- | `thoughts-analyzer` | Deep-dive analysis on research topics |
178
+ | `codebase-locator` | Locates files, directories, and components relevant to a feature or task |
179
+ | `codebase-pattern-finder` | Finds similar implementations and usage examples with concrete code snippets |
180
+ | `diff-auditor` | Walks a patch against a caller-supplied surface-list and emits `file:line \| verbatim \| surface-id \| note` rows |
181
+ | `integration-scanner` | Maps inbound references, outbound dependencies, config registrations, and event subscriptions for a component |
182
+ | `peer-comparator` | Compares a new file against a peer sibling and tags each invariant Mirrored / Missing / Diverged / Intentionally-absent |
183
+ | `precedent-locator` | Finds similar past changes in git history — commits, blast radius, and follow-up fixes |
184
+ | `test-case-locator` | Catalogs existing manual test cases under `.rpiv/test-cases/` and reports coverage stats |
185
+ | `thoughts-analyzer` | Performs deep-dive analysis on a research topic in `thoughts/` |
170
186
  | `thoughts-locator` | Discovers relevant documents in the `thoughts/` directory |
171
- | `web-search-researcher` | Researches web-based information and documentation |
187
+ | `web-search-researcher` | Researches modern web-only information via deep search and fetch |
172
188
 
173
189
  ## Architecture
174
190
 
@@ -194,6 +210,8 @@ Pi Agent discovers extensions via `"extensions": ["./extensions"]` and skills vi
194
210
 
195
211
  rpiv-pi owns nicobailon's pi-subagents registration (runs it through an in-process proxy so the inline tool card stays quiet and the Subagents overlay is the live view). `/rpiv-setup` strips `"npm:pi-subagents"` from your `~/.pi/agent/settings.json#packages[]` to prevent Pi from loading it twice. If you remove rpiv-pi, subagents will stop loading until you re-add that entry.
196
212
 
213
+ The bundled built-in agents from `pi-subagents` (`scout`, `planner`, `oracle`, …) are hidden from both the `subagent` tool that the assistant dispatches to and the `/agents` manager overlay (and `ctrl+shift+a`). The overlay filter is best-effort — if a future `pi-subagents` release changes its manager UI, rpiv-pi will print one boot-time warning to stderr and the built-in rows will reappear in `/agents` until rpiv-pi ships an update. The assistant-side filter is unaffected by upstream changes. To re-enable a built-in agent yourself, edit `subagents.disableBuiltins` in `~/.pi/agent/settings.json` (set to `false` or delete the key) and restart Pi.
214
+
197
215
  To fully uninstall:
198
216
 
199
217
  1. Remove rpiv-pi from Pi: `pi uninstall npm:@juicesharp/rpiv-pi`
@@ -1,9 +1,8 @@
1
1
  ---
2
2
  name: general-purpose
3
3
  description: "General-purpose agent for researching complex questions, searching for code, and executing multi-step tasks. When you are searching for a keyword or file and are not confident that you will find the right match in the first few tries use this agent to perform the search for you."
4
- tools: read, grep, find, ls, bash
5
- systemPromptMode: replace
6
- inheritProjectContext: false
4
+ systemPromptMode: append
5
+ inheritProjectContext: true
7
6
  inheritSkills: false
8
7
  ---
9
8
 
@@ -0,0 +1,149 @@
1
+ import { describe, expect, it, vi } from "vitest";
2
+ import {
3
+ __resetManagerRowFilterForTests,
4
+ INSTALLED_SENTINEL,
5
+ installManagerRowFilter,
6
+ LOAD_ENTRIES_SOURCE_FRAGMENT,
7
+ type SkipReason,
8
+ } from "./hide-builtin-manager-rows.js";
9
+
10
+ interface AgentEntry {
11
+ name: string;
12
+ }
13
+ interface AgentDataFixture {
14
+ builtin: AgentEntry[];
15
+ user: AgentEntry[];
16
+ project: AgentEntry[];
17
+ }
18
+ interface ManagerLike {
19
+ agentData: AgentDataFixture;
20
+ _walkedBuiltin: string[];
21
+ }
22
+
23
+ // Synthetic constructor whose `loadEntries` mirrors the load-bearing shape
24
+ // of upstream agent-manager.ts:120-124 — references `this.agentData.builtin`
25
+ // (drift anchor) and walks it, recording names into a side-channel so tests
26
+ // can assert what would have been rendered.
27
+ function makeFixtureCtor(): new () => ManagerLike {
28
+ function FixtureCtor(this: ManagerLike) {
29
+ this.agentData = { builtin: [], user: [], project: [] };
30
+ this._walkedBuiltin = [];
31
+ }
32
+ FixtureCtor.prototype.loadEntries = function (this: ManagerLike) {
33
+ this._walkedBuiltin = [];
34
+ // Keep the literal substring so the drift guard accepts this fixture.
35
+ for (const config of this.agentData.builtin) {
36
+ this._walkedBuiltin.push(config.name);
37
+ }
38
+ };
39
+ return FixtureCtor as unknown as new () => ManagerLike;
40
+ }
41
+
42
+ describe("installManagerRowFilter", () => {
43
+ it("filters PI_SUBAGENTS_BUILTINS rows from the walked list", () => {
44
+ const Ctor = makeFixtureCtor();
45
+ const result = installManagerRowFilter(Ctor);
46
+ expect(result).toBe("installed");
47
+
48
+ const instance = new Ctor();
49
+ instance.agentData = {
50
+ builtin: [{ name: "scout" }, { name: "planner" }, { name: "general-purpose" }, { name: "codebase-locator" }],
51
+ user: [],
52
+ project: [],
53
+ };
54
+ instance._walkedBuiltin = [];
55
+ instance.constructor.prototype.loadEntries.call(instance);
56
+
57
+ expect(instance._walkedBuiltin).toEqual(["general-purpose", "codebase-locator"]);
58
+ __resetManagerRowFilterForTests();
59
+ });
60
+
61
+ it("filters on every invocation (covers refreshAgentData re-call)", () => {
62
+ const Ctor = makeFixtureCtor();
63
+ installManagerRowFilter(Ctor);
64
+ const instance = new Ctor();
65
+
66
+ instance.agentData = { builtin: [{ name: "scout" }, { name: "thoughts-locator" }], user: [], project: [] };
67
+ instance.constructor.prototype.loadEntries.call(instance);
68
+ expect(instance._walkedBuiltin).toEqual(["thoughts-locator"]);
69
+
70
+ instance.agentData = { builtin: [{ name: "oracle" }, { name: "diff-auditor" }], user: [], project: [] };
71
+ instance.constructor.prototype.loadEntries.call(instance);
72
+ expect(instance._walkedBuiltin).toEqual(["diff-auditor"]);
73
+
74
+ __resetManagerRowFilterForTests();
75
+ });
76
+
77
+ it("restores the unfiltered agentData reference after loadEntries returns", () => {
78
+ const Ctor = makeFixtureCtor();
79
+ installManagerRowFilter(Ctor);
80
+ const instance = new Ctor();
81
+ const unfiltered = {
82
+ builtin: [{ name: "scout" }, { name: "general-purpose" }],
83
+ user: [],
84
+ project: [],
85
+ };
86
+ instance.agentData = unfiltered;
87
+ instance.constructor.prototype.loadEntries.call(instance);
88
+
89
+ expect(instance.agentData).toBe(unfiltered);
90
+ expect(instance.agentData.builtin.map((c) => c.name)).toEqual(["scout", "general-purpose"]);
91
+ __resetManagerRowFilterForTests();
92
+ });
93
+
94
+ it("is idempotent — second install returns 'skipped' with reason 'already-installed'", () => {
95
+ const Ctor = makeFixtureCtor();
96
+ const first = installManagerRowFilter(Ctor);
97
+ const patched = (Ctor.prototype as { loadEntries: () => void }).loadEntries;
98
+
99
+ const onSkip = vi.fn<(reason: SkipReason) => void>();
100
+ const second = installManagerRowFilter(Ctor, { onSkip });
101
+ expect(first).toBe("installed");
102
+ expect(second).toBe("skipped");
103
+ expect(onSkip).toHaveBeenCalledWith("already-installed");
104
+ expect((Ctor.prototype as { loadEntries: () => void }).loadEntries).toBe(patched);
105
+ expect((Ctor as { [INSTALLED_SENTINEL]?: boolean })[INSTALLED_SENTINEL]).toBe(true);
106
+
107
+ __resetManagerRowFilterForTests();
108
+ });
109
+
110
+ it.each<[string, unknown, SkipReason]>([
111
+ ["missing constructor (undefined)", undefined, "missing-constructor"],
112
+ ["missing constructor (null)", null, "missing-constructor"],
113
+ ["missing prototype", { prototype: undefined }, "missing-prototype"],
114
+ ["missing loadEntries", { prototype: {} }, "missing-loadentries"],
115
+ ["loadEntries lacks drift anchor", { prototype: { loadEntries: () => 1 } }, "drift-detected"],
116
+ ])("fails soft on %s — onSkip(%s) and never throws", (_label, ctor, expectedReason) => {
117
+ const onSkip = vi.fn<(reason: SkipReason) => void>();
118
+ expect(() => installManagerRowFilter(ctor, { onSkip })).not.toThrow();
119
+ expect(onSkip).toHaveBeenCalledExactlyOnceWith(expectedReason);
120
+ });
121
+
122
+ it("survives invocation when agentData.builtin is missing", () => {
123
+ const Ctor = makeFixtureCtor();
124
+ installManagerRowFilter(Ctor);
125
+ const instance = new Ctor();
126
+ instance.agentData = { builtin: undefined as unknown as AgentEntry[], user: [], project: [] };
127
+ expect(() => instance.constructor.prototype.loadEntries.call(instance)).not.toThrow();
128
+ __resetManagerRowFilterForTests();
129
+ });
130
+ });
131
+
132
+ describe("real pi-subagents AgentManagerComponent contract", () => {
133
+ // Canary: this is the only test that touches the live upstream module.
134
+ // Failing here means upstream pi-subagents drifted between our pin and
135
+ // our release — bump the dep, update LOAD_ENTRIES_SOURCE_FRAGMENT (or
136
+ // retire the patch), and re-snapshot. At user runtime the patch fails
137
+ // soft via onSkip; this test exists so we catch drift before shipping.
138
+ it("loadEntries body still contains the load-bearing drift anchor", async () => {
139
+ // Dynamic import: matches the runtime guarded import in renderer-override.ts
140
+ // and avoids tsc resolving into the upstream .ts source via the path stub.
141
+ const mod = (await import("pi-subagents/agent-manager")) as {
142
+ AgentManagerComponent?: { prototype?: { loadEntries?: () => void } };
143
+ };
144
+ const proto = mod.AgentManagerComponent?.prototype;
145
+ const fn = proto?.loadEntries;
146
+ expect(typeof fn).toBe("function");
147
+ expect(fn?.toString()).toContain(LOAD_ENTRIES_SOURCE_FRAGMENT);
148
+ });
149
+ });
@@ -0,0 +1,129 @@
1
+ // Hides the upstream pi-subagents built-in agent rows from the `/agents`
2
+ // manager overlay (and ctrl+shift+a). Companion to hide-builtin-subagents.ts,
3
+ // which hides the same names from the LLM-facing `subagent` tool surface.
4
+ //
5
+ // Strategy: monkey-patch `AgentManagerComponent.prototype.loadEntries` — the
6
+ // single chokepoint that converts agentData → rendered AgentEntry rows. The
7
+ // constructor calls it, refreshAgentData() calls it after every in-overlay
8
+ // mutation, so one patch covers both code paths.
9
+ //
10
+ // Fail-soft contract: never throw at user runtime. Drift, missing class, or
11
+ // missing method routes through the caller-supplied `onSkip` so Pi can
12
+ // surface a single warning notify and continue booting. The /agents overlay
13
+ // silently regains the upstream rows; the LLM-facing filter (Proxy in
14
+ // renderer-override.ts) is unaffected because it lives on a different layer.
15
+
16
+ import { PI_SUBAGENTS_BUILTINS } from "./hide-builtin-subagents.js";
17
+
18
+ const BUILTIN_NAMES_SET = new Set<string>(PI_SUBAGENTS_BUILTINS);
19
+
20
+ // Drift anchor: the load-bearing substring inside upstream
21
+ // agent-manager.ts:120-124 loadEntries. If upstream rewrites the method to
22
+ // stop reading agentData.builtin (rename, inline into ctor, route through a
23
+ // helper), this fragment disappears and we skip with reason "drift-detected"
24
+ // before mutating the prototype.
25
+ export const LOAD_ENTRIES_SOURCE_FRAGMENT = "this.agentData.builtin";
26
+
27
+ export const INSTALLED_SENTINEL = Symbol.for("rpiv-pi.manager-row-filter-installed");
28
+
29
+ export type InstallResult = "installed" | "skipped";
30
+
31
+ export type SkipReason =
32
+ | "missing-constructor"
33
+ | "missing-prototype"
34
+ | "missing-loadentries"
35
+ | "drift-detected"
36
+ | "already-installed";
37
+
38
+ export interface InstallOptions {
39
+ onSkip?: (reason: SkipReason) => void;
40
+ }
41
+
42
+ interface AgentDataLike {
43
+ builtin?: Array<{ name?: unknown }>;
44
+ }
45
+
46
+ interface ManagerInstanceLike {
47
+ agentData?: AgentDataLike;
48
+ }
49
+
50
+ interface ManagerCtorLike {
51
+ prototype?: { loadEntries?: (this: ManagerInstanceLike) => void };
52
+ [INSTALLED_SENTINEL]?: boolean;
53
+ }
54
+
55
+ interface PatchRecord {
56
+ ctor: ManagerCtorLike;
57
+ original: (this: ManagerInstanceLike) => void;
58
+ }
59
+
60
+ let installedPatch: PatchRecord | undefined;
61
+
62
+ function isFilteredBuiltin(entry: { name?: unknown }): boolean {
63
+ return typeof entry.name === "string" && BUILTIN_NAMES_SET.has(entry.name);
64
+ }
65
+
66
+ export function installManagerRowFilter(managerCtor: unknown, options: InstallOptions = {}): InstallResult {
67
+ const onSkip = options.onSkip ?? (() => {});
68
+ const ctor = managerCtor as ManagerCtorLike | undefined | null;
69
+
70
+ if (!ctor) {
71
+ onSkip("missing-constructor");
72
+ return "skipped";
73
+ }
74
+ if (ctor[INSTALLED_SENTINEL] === true) {
75
+ onSkip("already-installed");
76
+ return "skipped";
77
+ }
78
+ const proto = ctor.prototype;
79
+ if (!proto) {
80
+ onSkip("missing-prototype");
81
+ return "skipped";
82
+ }
83
+ const original = proto.loadEntries;
84
+ if (typeof original !== "function") {
85
+ onSkip("missing-loadentries");
86
+ return "skipped";
87
+ }
88
+ let source: string;
89
+ try {
90
+ source = original.toString();
91
+ } catch {
92
+ onSkip("drift-detected");
93
+ return "skipped";
94
+ }
95
+ if (!source.includes(LOAD_ENTRIES_SOURCE_FRAGMENT)) {
96
+ onSkip("drift-detected");
97
+ return "skipped";
98
+ }
99
+
100
+ proto.loadEntries = function patchedLoadEntries(this: ManagerInstanceLike): void {
101
+ // Defensive clone: never mutate the agentData reference we received.
102
+ // Other manager screens (override-scope, edit) read agentData directly
103
+ // and may rely on the unfiltered shape.
104
+ const original = this.agentData;
105
+ const builtin = Array.isArray(original?.builtin) ? original.builtin : [];
106
+ const filteredBuiltin = builtin.filter((c) => !isFilteredBuiltin(c ?? {}));
107
+ const filteredAgentData = { ...(original ?? {}), builtin: filteredBuiltin };
108
+ this.agentData = filteredAgentData as AgentDataLike;
109
+ try {
110
+ (installedPatch?.original ?? (() => {})).call(this);
111
+ } finally {
112
+ // Restore the unfiltered view for downstream reads outside loadEntries.
113
+ this.agentData = original;
114
+ }
115
+ };
116
+ ctor[INSTALLED_SENTINEL] = true;
117
+ installedPatch = { ctor, original };
118
+ return "installed";
119
+ }
120
+
121
+ // Test-only: undo the prototype mutation so each test sees a fresh slate.
122
+ // Wired into test/setup.ts beforeEach. No-op when nothing is installed.
123
+ export function __resetManagerRowFilterForTests(): void {
124
+ if (!installedPatch) return;
125
+ const { ctor, original } = installedPatch;
126
+ if (ctor.prototype) ctor.prototype.loadEntries = original;
127
+ delete ctor[INSTALLED_SENTINEL];
128
+ installedPatch = undefined;
129
+ }
@@ -0,0 +1,14 @@
1
+ /**
2
+ * Compile-time stub for `pi-subagents/agent-manager` — see `./index.d.ts`
3
+ * for the stub rationale.
4
+ *
5
+ * Surface kept opaque on purpose: we touch exactly one thing on this
6
+ * class — `prototype.loadEntries` — via a runtime prototype patch in
7
+ * hide-builtin-manager-rows.ts. Typing the full upstream class (30+
8
+ * private fields, a dozen managed screens) would force us to mirror
9
+ * internal state we never read.
10
+ */
11
+
12
+ export declare class AgentManagerComponent {
13
+ private readonly __piSubagentsAgentManagerComponent: true;
14
+ }
@@ -63,6 +63,19 @@ Example: { chain: [{agent:"scout", task:"Analyze {task}"}, {agent:"planner", tas
63
63
  });
64
64
  vi.mock("pi-subagents", () => ({ default: registerSubagentExtensionMock }));
65
65
  vi.mock("pi-subagents/render", () => ({ renderSubagentResult: vi.fn() }));
66
+ // Stub AgentManagerComponent for the manager-row-filter install. Body
67
+ // includes "this.agentData.builtin" to satisfy the drift anchor — the
68
+ // install path is exercised end-to-end without touching the real upstream
69
+ // class. Per-test prototype reset is wired in test/setup.ts.
70
+ vi.mock("pi-subagents/agent-manager", () => {
71
+ class AgentManagerComponent {
72
+ agentData: { builtin: Array<{ name: string }> } = { builtin: [] };
73
+ loadEntries() {
74
+ void this.agentData.builtin;
75
+ }
76
+ }
77
+ return { AgentManagerComponent };
78
+ });
66
79
 
67
80
  import { registerSubagentsWithQuietRenderer } from "./renderer-override.js";
68
81
 
@@ -6,6 +6,7 @@
6
6
  import type { ExtensionAPI } from "@mariozechner/pi-coding-agent";
7
7
  import registerSubagentExtension from "pi-subagents";
8
8
  import { buildAgentEnumDescription } from "./agent-catalog.js";
9
+ import { installManagerRowFilter, type SkipReason } from "./hide-builtin-manager-rows.js";
9
10
  import {
10
11
  filterDisabledFromListResult,
11
12
  getCuratedSubagentDescription,
@@ -87,6 +88,33 @@ function interceptRegisterTool(pi: ExtensionAPI): ExtensionAPI {
87
88
  });
88
89
  }
89
90
 
91
+ // Fail-soft install: the /agents overlay row-filter is best-effort UI polish
92
+ // tied to pi-subagents@0.17.5 internals (AgentManagerComponent.prototype.
93
+ // loadEntries). On any drift — module moved, class renamed, method body
94
+ // changed — we log one stderr line and continue. The LLM-side filter
95
+ // (interceptRegisterTool above) lives entirely on our boundary and is
96
+ // unaffected. See hide-builtin-manager-rows.ts for skip-reason semantics.
97
+ async function tryInstallManagerRowFilter(): Promise<void> {
98
+ let mod: { AgentManagerComponent?: unknown };
99
+ try {
100
+ mod = (await import("pi-subagents/agent-manager")) as { AgentManagerComponent?: unknown };
101
+ } catch {
102
+ process.stderr.write(
103
+ "[rpiv-pi] /agents overlay built-in filter disabled: pi-subagents/agent-manager not found.\n",
104
+ );
105
+ return;
106
+ }
107
+ installManagerRowFilter(mod.AgentManagerComponent, {
108
+ onSkip: (reason: SkipReason) => {
109
+ if (reason === "already-installed") return;
110
+ process.stderr.write(
111
+ `[rpiv-pi] /agents overlay built-in filter disabled (${reason}); built-in agents will be visible until rpiv-pi updates.\n`,
112
+ );
113
+ },
114
+ });
115
+ }
116
+
90
117
  export async function registerSubagentsWithQuietRenderer(pi: ExtensionAPI): Promise<void> {
118
+ await tryInstallManagerRowFilter();
91
119
  await registerSubagentExtension(interceptRegisterTool(pi));
92
120
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juicesharp/rpiv-pi",
3
- "version": "0.12.4",
3
+ "version": "0.12.6",
4
4
  "description": "Skill-based development workflow for Pi Agent — discover, research, design, plan, implement, validate",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -22,7 +22,7 @@ Use the current working directory as the target project by default. If the user
22
22
  - This ensures you have full context before decomposing the work
23
23
 
24
24
  2. **Pass 1 — Map the project (parallel agents):**
25
- - Dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
25
+ - Dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
26
26
 
27
27
  **Agent A — Project tree mapping:**
28
28
  - agent: `codebase-locator`
@@ -75,7 +75,7 @@ Use the current working directory as the target project by default. If the user
75
75
  - Adjust the target list based on user feedback
76
76
 
77
77
  4. **Pass 2 — Analyze each layer (parallel analyzer agents):**
78
- - For each confirmed target folder, dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
78
+ - For each confirmed target folder, dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
79
79
 
80
80
  **For each target folder, spawn TWO agents:**
81
81
 
@@ -286,7 +286,7 @@ See the following for well-formed subfolder architecture.md examples:
286
286
  - Folder is a simple grouping without unique constraints
287
287
 
288
288
  ## Important notes:
289
- - Parallel subagent dispatch — one `subagent(...)` call per agent in a SINGLE tool-use batch (same response), never sequentially. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
289
+ - Parallel subagent dispatch — every `subagent(...)` call in the same assistant message (multiple tool_use blocks in one response), never one per turn. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
290
290
  - **File reading**: Always read mentioned files FULLY (no limit/offset) before invoking skills
291
291
  - **Critical ordering**: Follow the numbered steps exactly
292
292
  - ALWAYS read mentioned files first before invoking skills (step 1)
@@ -22,7 +22,7 @@ Use the current working directory as the target project by default. If the user
22
22
  - This ensures you have full context before decomposing the work
23
23
 
24
24
  2. **Pass 1 — Map the project (parallel agents):**
25
- - Dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
25
+ - Dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
26
26
 
27
27
  **Agent A — Project tree mapping:**
28
28
  - agent: `codebase-locator`
@@ -73,7 +73,7 @@ Use the current working directory as the target project by default. If the user
73
73
  - Adjust the target list based on user feedback
74
74
 
75
75
  4. **Pass 2 — Analyze each layer (parallel analyzer agents):**
76
- - For each confirmed target folder, dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
76
+ - For each confirmed target folder, dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
77
77
 
78
78
  **For each target folder, spawn TWO agents:**
79
79
 
@@ -282,7 +282,7 @@ See the following for well-formed subfolder CLAUDE.md examples:
282
282
  - Folder is a simple grouping without unique constraints
283
283
 
284
284
  ## Important notes:
285
- - Parallel subagent dispatch — one `subagent(...)` call per agent in a SINGLE tool-use batch (same response), never sequentially. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
285
+ - Parallel subagent dispatch — every `subagent(...)` call in the same assistant message (multiple tool_use blocks in one response), never one per turn. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
286
286
  - **File reading**: Always read mentioned files FULLY (no limit/offset) before invoking skills
287
287
  - **Critical ordering**: Follow the numbered steps exactly
288
288
  - ALWAYS read mentioned files first before invoking skills (step 1)
@@ -69,7 +69,7 @@ Every Wave-2 agent prompt contains EXACTLY: (a) `Known Context:` followed by the
69
69
 
70
70
  ## Step 2: Dispatch Wave-1 — Integration + Precedents + Deps/CVE + Peer-Mirror
71
71
 
72
- Dispatch ALL agents below at T=0 in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })` (isolated conversation per agent). Do NOT wait for integration-scanner before dispatching precedents / dependencies / CVE — they do not consume Discovery-Map output, only `ChangedFiles` and the manifest diff (both orchestrator-produced in Step 1). Wait for all to return before proceeding.
72
+ Dispatch ALL agents below at T=0 as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })` (isolated conversation per agent). Do NOT wait for integration-scanner before dispatching precedents / dependencies / CVE — they do not consume Discovery-Map output, only `ChangedFiles` and the manifest diff (both orchestrator-produced in Step 1). Wait for all to return before proceeding.
73
73
 
74
74
  **Agent — Integration map:**
75
75
  - agent: `integration-scanner`
@@ -152,7 +152,7 @@ Peer mirrors: [peer-mirror agent output verbatim — Missing/Diverged rows only;
152
152
 
153
153
  ## Step 3: Dispatch Wave-2 — Quality + Security Lenses
154
154
 
155
- Dispatch Quality + Security in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })` (isolated conversation per agent). Each receives the `## Discovery Map` block inline as `Known Context` above its task, and a pointer to `.git/code-review-patch.diff` for the diff itself. Precedents / Dependencies / CVE are already running from Wave-1 — do NOT re-dispatch them here; the prompts below document what those Wave-1 agents received, they are not re-issued.
155
+ Dispatch Quality + Security as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })` (isolated conversation per agent). Each receives the `## Discovery Map` block inline as `Known Context` above its task, and a pointer to `.git/code-review-patch.diff` for the diff itself. Precedents / Dependencies / CVE are already running from Wave-1 — do NOT re-dispatch them here; the prompts below document what those Wave-1 agents received, they are not re-issued.
156
156
 
157
157
  **Wave-2 context isolation (LOAD-BEARING — violations cause silent quality collapse)**: Each Wave-2 agent receives EXACTLY two things, nothing else: (1) the Discovery Map (digested form) and (2) the literal path string `.git/code-review-patch.diff`.
158
158
 
@@ -52,7 +52,7 @@ When this command is invoked:
52
52
 
53
53
  This is NOT a discovery sweep. Focus on DEPTH (how things work, what patterns to follow) not BREADTH (where things are).
54
54
 
55
- 1. **Dispatch all agents below in a SINGLE tool-use batch** one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
55
+ 1. **Dispatch all agents below as parallel `subagent` tool calls in the same assistant message** multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
56
56
 
57
57
  - Use **codebase-pattern-finder** to find existing implementations to model after — the primary template for code shape
58
58
  - Use **codebase-analyzer** to understand HOW integration points work in detail
@@ -387,7 +387,7 @@ The artifact was created as a skeleton in Step 6 and filled progressively in Ste
387
387
  | Novel work (new library/pattern) | + web-search-researcher |
388
388
  | During code writing (if needed) | targeted codebase-analyzer for specific files |
389
389
 
390
- When agents are searching for different things, dispatch them in a SINGLE tool-use batch — one `subagent(...)` call per agent in the SAME response (parallel tool calls, not sequential turns). Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Each agent runs in isolation — provide complete context in the prompt, including specific directory paths when the feature targets a known module. Don't write detailed prompts about HOW to search — just tell it what you're looking for and where.
390
+ When agents are searching for different things, dispatch them as parallel `subagent(...)` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Each agent runs in isolation — provide complete context in the prompt, including specific directory paths when the feature targets a known module. Don't write detailed prompts about HOW to search — just tell it what you're looking for and where.
391
391
 
392
392
  ## Important Notes
393
393
 
@@ -55,7 +55,7 @@ Before Step 1, create a todo list tracking every step below (Step 1 through Step
55
55
 
56
56
  This plan stays internal — do NOT present it to the developer unless asked.
57
57
 
58
- 3. **Dispatch all discovery agents in a SINGLE tool-use batch** one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
58
+ 3. **Dispatch all discovery agents as parallel `subagent` tool calls in the same assistant message** multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
59
59
 
60
60
  - Use **codebase-locator** for "Where do these files/symbols live?" slices — spawn one per focused code/discovery seam. Prefer 5-9 narrow discovery agents over 2-3 broad ones when the topic spans multiple subsystems.
61
61
  - Use **thoughts-locator** only for historical docs, decisions, plans, and prior artifacts about the topic
@@ -322,7 +322,7 @@ Wait for ALL agents to complete before proceeding.
322
322
 
323
323
  ## Important Notes
324
324
 
325
- - Parallel subagent dispatch — one `subagent(...)` call per agent in a SINGLE tool-use batch (same response), never sequentially. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
325
+ - Parallel subagent dispatch — every `subagent(...)` call in the same assistant message (multiple tool_use blocks in one response), never one per turn. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
326
326
  - Always spawn fresh research to validate current state - never rely on old research docs as source of truth
327
327
  - Old research documents can provide historical context but must be validated against current code
328
328
  - Generate 2-4 named candidates in Step 2; confirm them with the developer at Step 3 before per-candidate fit dispatch
@@ -51,7 +51,7 @@ Report detected mode:
51
51
 
52
52
  First, detect the project's technology stack by checking for framework indicators (see Framework Detection Reference below).
53
53
 
54
- Dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
54
+ Dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
55
55
  - Use the **codebase-locator** agent to find all registered routes, navigation menus, and page entry points
56
56
  - Use the **codebase-locator** agent to find all frontend HTTP API call sites — report each call-site `file:line` and the literal URL template string found at the call site (e.g., ``${base}/users/${id}``). Frontend-to-backend URL correlation happens orchestrator-side in Step 3's Cross-Reference synthesis (`skills/outline-test-cases/SKILL.md:71-79`) using the backend-controller findings from the next agent.
57
57
  - Use the **codebase-locator** agent to find all backend API controllers and route handlers
@@ -47,7 +47,7 @@ You are tasked with answering structured research questions by spawning targeted
47
47
 
48
48
  ## Step 2: Dispatch Analysis Agents
49
49
 
50
- Dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
50
+ Dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
51
51
 
52
52
  **Default agent**: `codebase-analyzer` for all codebase questions. This agent has Read, Grep, Glob, LS — it can trace code paths, find patterns, and analyze integration points.
53
53
 
@@ -45,7 +45,7 @@ Then wait for the user's input.
45
45
  - Other notes
46
46
 
47
47
  2. **Spawn focused research agents**:
48
- After reading all critical handoff/plan/research documents directly, dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
48
+ After reading all critical handoff/plan/research documents directly, dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
49
49
 
50
50
  ```
51
51
  Task 1 - Gather artifact context:
@@ -78,7 +78,7 @@ When this command is invoked:
78
78
 
79
79
  If the user's feedback requires understanding new code patterns or validating assumptions:
80
80
 
81
- 1. **Dispatch all agents below in a SINGLE tool-use batch** one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
81
+ 1. **Dispatch all agents below as parallel `subagent` tool calls in the same assistant message** multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
82
82
  **For code investigation:**
83
83
  - Use the **codebase-locator** agent to find relevant files
84
84
  - Use the **codebase-analyzer** agent to understand implementation details
@@ -217,7 +217,7 @@ When updating success criteria, always maintain the two-category structure:
217
217
  When spawning research agents:
218
218
 
219
219
  1. **Only spawn if truly needed** - don't research for simple changes
220
- 2. **Parallel dispatch** — one `subagent(...)` call per agent in a SINGLE tool-use batch (same response), never sequentially. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
220
+ 2. **Parallel dispatch** — every `subagent(...)` call in the same assistant message (multiple tool_use blocks in one response), never one per turn. Call shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`.
221
221
  3. **Each agent should be focused** on a specific area
222
222
  4. **Provide detailed instructions** including:
223
223
  - Exactly what to search for
@@ -49,7 +49,7 @@ If starting fresh or need more context:
49
49
 
50
50
  3. **Spawn parallel research agents** to verify implementation:
51
51
 
52
- Dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
52
+ Dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
53
53
  - **general-purpose** agent — Verify implementation details match plan specifications (analyzer role)
54
54
  - **general-purpose** agent — Verify implementation follows established codebase patterns (pattern-finder role)
55
55
 
@@ -70,7 +70,7 @@ When no _meta.md, detect the project's technology stack before spawning agents:
70
70
 
71
71
  ### Step 2: Discover Feature Code (parallel agents)
72
72
 
73
- Dispatch all agents below in a SINGLE tool-use batch one call per agent in the SAME response (parallel tool calls, not sequential turns). Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
73
+ Dispatch all agents below as parallel `subagent` tool calls in the same assistant message multiple tool_use blocks in one response, not one call per turn. Each call matches this shape: `subagent({ agent: "<agent-name>", task: "<task>", context: "fresh", artifacts: false })`. Wait for all to return before proceeding.
74
74
 
75
75
  **Agent A — Web Layer Discovery:**
76
76
  - agent: `codebase-locator`