@hk_net/pi-advisor 0.1.7 → 0.1.9
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/CHANGELOG.md +20 -0
- package/LICENSE +3 -0
- package/README.md +22 -11
- package/advisor.ts +53 -22
- package/package.json +22 -5
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,25 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.1.9 - 2026-08-23
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- Add the copyright holder and EUPL licensing notice to the package license and canonical TypeScript source.
|
|
8
|
+
- Identify KAPPER NETWORK-COMMUNICATIONS GmbH and kapper.net in the npm author metadata.
|
|
9
|
+
|
|
10
|
+
## 0.1.8 - 2026-08-23
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- Mark Pi's host-provided SDK packages as optional wildcard peers so npm does not install a redundant Pi SDK dependency tree.
|
|
15
|
+
- Verify development and tests against Pi SDK 0.84.2 while retaining runtime compatibility with Pi 0.84.1 and newer.
|
|
16
|
+
- Refine advisor tool guidance so non-trivial tasks require a review at an evidence-backed checkpoint before the final answer without encouraging an immediate first-action call.
|
|
17
|
+
- Make reviewer responses checkpoint-aware, evidence-grounded, and limited to a verdict plus three prioritized actions.
|
|
18
|
+
- Prevent `/advisor` from writing project-scoped configuration until Pi trusts the project.
|
|
19
|
+
- Run `onDone` review only after Pi fully settles retries, compaction recovery, and queued continuations.
|
|
20
|
+
- Write advisor configuration atomically with owner-only file permissions where supported.
|
|
21
|
+
- Document that the individual package and GitHub bundle must not be installed together.
|
|
22
|
+
|
|
3
23
|
## 0.1.7 - 2026-08-13
|
|
4
24
|
|
|
5
25
|
### Changed
|
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# pi-advisor
|
|
2
2
|
|
|
3
|
-
A [
|
|
3
|
+
A [Pi](https://www.npmjs.com/package/@earendil-works/pi-coding-agent) extension for Pi 0.84.1 or newer (tested with the current Pi 0.84.2 release) that offers a
|
|
4
4
|
parameterless `advisor` tool — inspired by Claude Code's advisor, but expanded with additional
|
|
5
5
|
nudges and a manual review procedure. The regular model calls `advisor` to get a second opinion
|
|
6
6
|
from an explicitly configured **stronger reviewer model** that sees the *entire* conversation transcript. Beyond the
|
|
@@ -11,24 +11,33 @@ or finishes a task, and the human can invoke a manual review via `/advise`.
|
|
|
11
11
|
|
|
12
12
|
When the model calls `advisor` (no arguments), the extension serializes the full active branch —
|
|
13
13
|
user/assistant text, assistant **reasoning**, every **tool call (with args)** and its **result** —
|
|
14
|
-
and forwards it to a stronger reviewer model with a reviewer system prompt. The reviewer
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
and forwards it to a stronger reviewer model with a reviewer system prompt. The reviewer infers whether it is assessing a plan,
|
|
15
|
+
a concrete failure, or claimed completion; checks the work against user and repository instructions
|
|
16
|
+
and primary-source evidence; and returns a verdict plus at most three prioritized actions. A
|
|
17
|
+
premature consultation asks for the specific missing evidence instead of inventing a verdict.
|
|
18
|
+
Individual tool-call arguments are truncated at 800 characters and tool results at
|
|
17
19
|
2,000 characters so huge outputs do not dominate the review; after that, the transcript is truncated
|
|
18
20
|
oldest-first only if it would overflow the reviewer's context window.
|
|
19
21
|
|
|
20
22
|
Beyond the callable tool, the extension provides two additional ways to get advice:
|
|
21
23
|
|
|
22
|
-
- **Automatic nudges** — the tool's `promptGuidelines`
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
- **Automatic nudges** — the tool's `promptGuidelines` tell the model to call advisor at a
|
|
25
|
+
useful checkpoint in every non-trivial task: after enough investigation to form an
|
|
26
|
+
evidence-backed approach and before a consequential edit, when stuck, or after implementation
|
|
27
|
+
and verification before claiming completion. A mandatory pre-final check tells the model not to
|
|
28
|
+
finish non-trivial work unless it has called advisor at least once after gathering evidence.
|
|
29
|
+
The guidance explicitly prohibits an advisor call as the first action or while there is no
|
|
30
|
+
substantive evidence or work to review. Two opt-in
|
|
31
|
+
deterministic triggers (`onDone`, `whenStuck`) go further: they auto-consult the reviewer and
|
|
32
|
+
inject the feedback directly into the conversation so the agent sees it.
|
|
26
33
|
- **Manual review via `/advise`** — the human can invoke a one-off review at any time. Feedback
|
|
27
34
|
can be shown UI-only (informal, for the human), piped into the chat as a user message, or
|
|
28
35
|
injected as a steering message so the running agent sees and acts on it.
|
|
29
36
|
|
|
30
37
|
## Files & install
|
|
31
38
|
|
|
39
|
+
> **Avoid duplicate installation.** Install this npm package or the GitHub bundle, not both. Loading both copies can duplicate tools, commands, and automatic event handlers.
|
|
40
|
+
|
|
32
41
|
- `advisor.ts` — canonical source (this repo).
|
|
33
42
|
- Package-installed copy: loaded from this package's `pi.extensions` manifest after `pi install`.
|
|
34
43
|
|
|
@@ -118,8 +127,9 @@ Autocomplete completes `/adviso...` to `/advisor` without Pi's trailing-space in
|
|
|
118
127
|
Default **off** — out of the box the regular model decides when to call `advisor`, nudged by the
|
|
119
128
|
tool's `promptGuidelines`. Two opt-in deterministic triggers, configurable per project and global:
|
|
120
129
|
|
|
121
|
-
- **`onDone`** — on `
|
|
122
|
-
|
|
130
|
+
- **`onDone`** — on `agent_settled`, after automatic retries, compaction recovery, and queued
|
|
131
|
+
continuations finish, auto-review and steer one follow-up so the agent addresses any issues
|
|
132
|
+
before truly stopping (guarded to at most once per user prompt).
|
|
123
133
|
- **`whenStuck: N`** — after N consecutive tool errors **or** N repeated identical tool calls
|
|
124
134
|
(same tool name + same arguments), auto-consult the reviewer and inject the advice as a
|
|
125
135
|
steering message to get unstuck.
|
|
@@ -131,7 +141,8 @@ tool's `promptGuidelines`. Two opt-in deterministic triggers, configurable per p
|
|
|
131
141
|
another model.
|
|
132
142
|
- **Project config follows pi project trust.** A global install ignores `<cwd>/.pi/advisor.json`
|
|
133
143
|
while the current project is untrusted, so an untrusted checkout cannot silently choose a reviewer
|
|
134
|
-
model or enable auto-triggers.
|
|
144
|
+
model or enable auto-triggers. `/advisor` also withholds the project scope from its configuration
|
|
145
|
+
picker until the project is trusted; global configuration remains available.
|
|
135
146
|
- **Auto-triggers are off by default.** The `onDone` and `whenStuck` features must be explicitly
|
|
136
147
|
enabled in configuration, and they do nothing unless a reviewer model is configured.
|
|
137
148
|
- **Data sent to the reviewer model.** When `advisor` is called, the extension sends the full
|
package/advisor.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
// Copyright © 2026 kapper.net - KAPPER NETWORK-COMMUNICATIONS GmbH
|
|
2
|
+
// SPDX-License-Identifier: EUPL-1.2
|
|
3
|
+
|
|
1
4
|
/**
|
|
2
5
|
* advisor.ts — a pi extension inspired by Claude Code's `advisor` tool, expanded
|
|
3
6
|
* with automatic triggers and a human-invoked manual review command.
|
|
@@ -44,7 +47,7 @@ import { getSupportedThinkingLevels, Type } from "@earendil-works/pi-ai";
|
|
|
44
47
|
import type { Api, Model, ModelThinkingLevel, ProviderHeaders } from "@earendil-works/pi-ai";
|
|
45
48
|
import { complete } from "@earendil-works/pi-ai/compat";
|
|
46
49
|
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
47
|
-
import { getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
50
|
+
import { CONFIG_DIR_NAME, getMarkdownTheme } from "@earendil-works/pi-coding-agent";
|
|
48
51
|
import { Box, Markdown, SelectList, truncateToWidth } from "@earendil-works/pi-tui";
|
|
49
52
|
import type { AutocompleteItem, Component } from "@earendil-works/pi-tui";
|
|
50
53
|
import * as fs from "node:fs";
|
|
@@ -193,19 +196,28 @@ tool outputs, file contents, command output, or other transcript excerpts unless
|
|
|
193
196
|
are directly relevant to reviewing the coding agent's work. Do not quote secrets or
|
|
194
197
|
credentials unless strictly necessary to identify a concrete issue.
|
|
195
198
|
|
|
199
|
+
First infer the checkpoint: evidence gathering or plan review, recovery from a
|
|
200
|
+
concrete failure, or completion review. Judge the work appropriate to that checkpoint.
|
|
201
|
+
If the transcript is too early to support a useful review, say that plainly and name
|
|
202
|
+
the specific evidence the agent should gather next; do not invent a verdict.
|
|
203
|
+
|
|
196
204
|
Give direct, high-signal advice. Specifically:
|
|
205
|
+
- Check the user's actual goal, repository instructions, primary-source API evidence,
|
|
206
|
+
and existing project patterns before endorsing the approach.
|
|
197
207
|
- If the agent is about to build on a wrong assumption, a misread of a file, or a
|
|
198
208
|
flawed interpretation of the request, say so plainly and point at the evidence.
|
|
199
209
|
- If the approach is sound, confirm it and name the one or two things most likely to
|
|
200
210
|
bite — edge cases, missed requirements, or unverified claims.
|
|
201
|
-
- If the agent thinks it is done, scrutinize
|
|
202
|
-
a
|
|
211
|
+
- If the agent thinks it is done, scrutinize the actual changes and verification: is
|
|
212
|
+
a requirement left unmet, a claim unverified, or a test not exercising the behavior?
|
|
213
|
+
Do not manufacture unrelated scope or demand changes unsupported by the task.
|
|
203
214
|
- Prefer concrete next actions over generic best-practice lectures. Cite specific
|
|
204
|
-
files, functions, or transcript moments.
|
|
215
|
+
files, functions, commands, or transcript moments.
|
|
205
216
|
|
|
206
|
-
Be concise and decisive.
|
|
207
|
-
|
|
208
|
-
|
|
217
|
+
Be concise and decisive. Lead with a one-sentence verdict, followed by at most three
|
|
218
|
+
prioritized actions. If no corrective action is needed, say the work is ready and name
|
|
219
|
+
only any final verification still warranted. Do not restate the transcript back; the
|
|
220
|
+
agent already has it. Always return visible assistant text, never reasoning-only output.`;
|
|
209
221
|
|
|
210
222
|
// ── Config files ────────────────────────────────────────────────────────────
|
|
211
223
|
|
|
@@ -218,7 +230,14 @@ type AdvisorConfig = {
|
|
|
218
230
|
};
|
|
219
231
|
|
|
220
232
|
const globalConfigPath = () => path.join(os.homedir(), ".pi", "agent", "advisor.json");
|
|
221
|
-
const projectConfigPath = (cwd: string) => path.join(cwd,
|
|
233
|
+
const projectConfigPath = (cwd: string) => path.join(cwd, CONFIG_DIR_NAME, "advisor.json");
|
|
234
|
+
|
|
235
|
+
const PROJECT_SCOPE = "This folder (project)";
|
|
236
|
+
const GLOBAL_SCOPE = "Global (all projects)";
|
|
237
|
+
|
|
238
|
+
export function getAdvisorScopeChoices(projectTrusted: boolean): string[] {
|
|
239
|
+
return projectTrusted ? [PROJECT_SCOPE, GLOBAL_SCOPE] : [GLOBAL_SCOPE];
|
|
240
|
+
}
|
|
222
241
|
|
|
223
242
|
export function validateAdvisorConfig(raw: unknown, source = "advisor config"): AdvisorConfig {
|
|
224
243
|
const warn = (message: string) => console.warn(`[pi-advisor] Ignoring invalid ${source}: ${message}`);
|
|
@@ -282,7 +301,14 @@ function writeConfig(file: string, cfg: AdvisorConfig): void {
|
|
|
282
301
|
if (cfg.onDone !== undefined) clean.onDone = cfg.onDone;
|
|
283
302
|
if (cfg.whenStuck !== undefined) clean.whenStuck = cfg.whenStuck;
|
|
284
303
|
if (cfg.timeoutMs !== undefined) clean.timeoutMs = cfg.timeoutMs;
|
|
285
|
-
|
|
304
|
+
|
|
305
|
+
const temporaryFile = `${file}.tmp-${process.pid}-${Date.now()}`;
|
|
306
|
+
try {
|
|
307
|
+
fs.writeFileSync(temporaryFile, JSON.stringify(clean, null, 2) + "\n", { encoding: "utf-8", mode: 0o600 });
|
|
308
|
+
fs.renameSync(temporaryFile, file);
|
|
309
|
+
} finally {
|
|
310
|
+
fs.rmSync(temporaryFile, { force: true });
|
|
311
|
+
}
|
|
286
312
|
}
|
|
287
313
|
|
|
288
314
|
// ── Resolution ──────────────────────────────────────────────────────────────
|
|
@@ -797,14 +823,16 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
797
823
|
label: "Advisor",
|
|
798
824
|
description:
|
|
799
825
|
"Consult a configured stronger reviewer model that sees your full conversation transcript. " +
|
|
800
|
-
"
|
|
801
|
-
"
|
|
802
|
-
"
|
|
803
|
-
"
|
|
804
|
-
promptSnippet: "
|
|
826
|
+
"Use it only after the transcript contains substantive investigation, an evidence-backed plan, " +
|
|
827
|
+
"implementation work, or a concrete failure to review; do not call it as the first action. " +
|
|
828
|
+
"Takes NO parameters — if configured, the entire active conversation (task, reasoning, tool calls, " +
|
|
829
|
+
"and results) is forwarded automatically. If unconfigured, it sends nothing and returns setup guidance.",
|
|
830
|
+
promptSnippet: "Mandatory evidence-based review checkpoint for non-trivial work; never the first action",
|
|
805
831
|
promptGuidelines: [
|
|
806
|
-
"
|
|
807
|
-
"
|
|
832
|
+
"For every non-trivial task, you MUST call advisor at a useful checkpoint: after investigating enough context to form an evidence-backed approach and before the first consequential edit, when concrete failures recur or the approach stops converging, or after implementation and verification before claiming completion.",
|
|
833
|
+
"Before giving a final answer on any non-trivial task, verify that you called advisor at least once after gathering substantive evidence. If you have not, call advisor now and incorporate its result; do not finish the task without this review.",
|
|
834
|
+
"Never call advisor as the first action, merely to restate the user's request, or while the transcript contains no substantive evidence or work for a reviewer to assess. Trivial questions and mechanical edits do not require advisor.",
|
|
835
|
+
"advisor takes no arguments; if no reviewer model is configured, it sends nothing and returns setup guidance. Otherwise it forwards the whole conversation. Give its advice serious weight, but adapt when a suggestion fails empirically or contradicts primary-source evidence.",
|
|
808
836
|
],
|
|
809
837
|
parameters: Type.Object({}),
|
|
810
838
|
async execute(_toolCallId, _params, signal, onUpdate, ctx) {
|
|
@@ -871,8 +899,9 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
871
899
|
}
|
|
872
900
|
});
|
|
873
901
|
|
|
874
|
-
// "On done":
|
|
875
|
-
|
|
902
|
+
// "On done": after retries, compaction recovery, and queued continuations have
|
|
903
|
+
// fully settled, review and (if enabled) steer one follow-up.
|
|
904
|
+
pi.on("agent_settled", async (_event, ctx) => {
|
|
876
905
|
const projectTrusted = contextProjectTrusted(ctx);
|
|
877
906
|
const { onDone } = effectiveTriggers(ctx.cwd, projectTrusted);
|
|
878
907
|
if (!onDone || autoReviewedThisRound || autoRunning || isDisabled(ctx.cwd, projectTrusted) || isUnconfigured(ctx.cwd, projectTrusted)) return;
|
|
@@ -996,11 +1025,13 @@ export default function advisorExtension(pi: ExtensionAPI) {
|
|
|
996
1025
|
}
|
|
997
1026
|
|
|
998
1027
|
const pickScope = async (): Promise<string | undefined> => {
|
|
999
|
-
const
|
|
1000
|
-
|
|
1001
|
-
|
|
1028
|
+
const projectTrusted = contextProjectTrusted(ctx);
|
|
1029
|
+
if (!projectTrusted) {
|
|
1030
|
+
ctx.ui.notify("Project advisor settings cannot be changed until this project is trusted; only global scope is available.", "warning");
|
|
1031
|
+
}
|
|
1032
|
+
const scope = await ctx.ui.select("Apply to", getAdvisorScopeChoices(projectTrusted));
|
|
1002
1033
|
if (scope === undefined) return undefined;
|
|
1003
|
-
return scope ===
|
|
1034
|
+
return scope === PROJECT_SCOPE ? projectConfigPath(cwd) : globalConfigPath();
|
|
1004
1035
|
};
|
|
1005
1036
|
const persist = (file: string, patch: AdvisorConfig) => {
|
|
1006
1037
|
writeConfig(file, { ...readConfig(file), ...patch });
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hk_net/pi-advisor",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.9",
|
|
4
4
|
"description": "Pi advisor extension: consult a configured reviewer model on the full conversation transcript",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"private": false,
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
"advisor"
|
|
12
12
|
],
|
|
13
13
|
"license": "EUPL-1.2",
|
|
14
|
-
"author":
|
|
14
|
+
"author": {
|
|
15
|
+
"name": "KAPPER NETWORK-COMMUNICATIONS GmbH",
|
|
16
|
+
"url": "https://kapper.net"
|
|
17
|
+
},
|
|
15
18
|
"repository": {
|
|
16
19
|
"type": "git",
|
|
17
20
|
"url": "git+https://github.com/hknet/pi-extensions.git",
|
|
@@ -26,10 +29,24 @@
|
|
|
26
29
|
"README.md",
|
|
27
30
|
"CHANGELOG.md"
|
|
28
31
|
],
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=22.19.0"
|
|
34
|
+
},
|
|
29
35
|
"peerDependencies": {
|
|
30
|
-
"@earendil-works/pi-ai": "
|
|
31
|
-
"@earendil-works/pi-coding-agent": "
|
|
32
|
-
"@earendil-works/pi-tui": "
|
|
36
|
+
"@earendil-works/pi-ai": "*",
|
|
37
|
+
"@earendil-works/pi-coding-agent": "*",
|
|
38
|
+
"@earendil-works/pi-tui": "*"
|
|
39
|
+
},
|
|
40
|
+
"peerDependenciesMeta": {
|
|
41
|
+
"@earendil-works/pi-ai": {
|
|
42
|
+
"optional": true
|
|
43
|
+
},
|
|
44
|
+
"@earendil-works/pi-coding-agent": {
|
|
45
|
+
"optional": true
|
|
46
|
+
},
|
|
47
|
+
"@earendil-works/pi-tui": {
|
|
48
|
+
"optional": true
|
|
49
|
+
}
|
|
33
50
|
},
|
|
34
51
|
"pi": {
|
|
35
52
|
"extensions": [
|