@ian-pascoe/pi-advisor 0.0.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright 2026 Ian Pascoe
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,63 @@
1
+ # Pi Advisor
2
+
3
+ `@ian-pascoe/pi-advisor` reviews a Pi agent's completed work and surfaces concise, attributed corrective advice when it finds material instruction violations, scope drift, repeated failures, or unsupported completion claims.
4
+
5
+ Requires Pi `0.85.1` and Node `>=22.19.0`. Other Pi versions pause review with an explicit compatibility error.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pi install npm:@ian-pascoe/pi-advisor
11
+ # or from this checkout
12
+ pi -e ./packages/pi-advisor/src/index.ts
13
+ ```
14
+
15
+ Advisor is **disabled by default**. Configuration precedence is session, trusted project, global, then package defaults. Settings use Pi's native settings files and session entries; no separate database or transcript store is created.
16
+
17
+ ## Commands
18
+
19
+ ```text
20
+ /advisor status
21
+ /advisor on|off [--global|--project]
22
+ /advisor inherit [key] [--global|--project]
23
+ /advisor set <key> <JSON> [--global|--project]
24
+ /advisor prompt [--global|--project]
25
+ /advisor set includeSubagents true
26
+ /advisor set model "provider/model-id"
27
+ ```
28
+
29
+ Argument autocomplete suggests command names, settings keys, and valid trailing scope flags.
30
+
31
+ `prompt` opens Pi's native editor and replaces the whole Advisor Prompt. `inherit` removes an override at the selected scope. Invalid keys and values are rejected. Lists, including `allowedTools`, replace the inherited list rather than merge. `catchUpThreshold` accepts any positive safe integer or `"off"`; `reviewTimeoutMs` accepts 1–2,147,483,647 milliseconds (the native timer range).
32
+
33
+ ## Defaults and access
34
+
35
+ | Option | Default |
36
+ | ------------------------------ | ---------------------------- |
37
+ | Enabled | `false` |
38
+ | Watched sessions | Main only |
39
+ | Allowed tools | `read`, `grep`, `find`, `ls` |
40
+ | Catch-up threshold | `3` |
41
+ | Review deadline | 120 seconds |
42
+ | Investigative calls per Review | 8 |
43
+ | Automatic Corrective Turns | 1 per request/task |
44
+
45
+ A Tool Grant names tools; it does not sandbox their full native interfaces. Explicitly granting `lsp`, for example, permits its native operations, including mutations. Unavailable names are ignored and reported. CodeMode-only tools require an explicitly compatible transport grant; Advisor never adds aliases, autogrants missing tools, or changes CodeMode exposure.
46
+
47
+ The Advisor inherits each observed agent's model and thinking level independently unless configured otherwise. One root policy can cover current and future Minimal Subagents descendants when enabled.
48
+
49
+ ## Sessions and Context Management
50
+
51
+ Each watched agent has a private, persisted native Advisor Session with fresh, session-bound extension resources. Reviews reuse that session until context or configuration changes require rebuilding. Pi 0.85.1's hidden inline `llama.cpp` built-in is recreated from the installed Pi package's shipped extension file, retaining its ordered metadata and fresh provider state. This is a fixed-version compatibility recipe, not general inline-factory support; it requires the shipped file and the built-in's expected registration shape. Other opaque inline or custom extension resources that cannot be safely recreated are reported as unsupported and pause the Advisor; they are not silently reused or omitted. The Advisor's session state remains separate from the observed agent's state.
52
+
53
+ Context Management is optional. If loaded and its tools are granted, `context_notes`, `context_history`, and `context_rollover` operate on the Advisor's private context. If any of those three tools is excluded, the Advisor pauses before reviewing. There is no autogrant or hook bypass.
54
+
55
+ ## Scheduling and safety
56
+
57
+ Reviews combine completed observed turns (one model response plus its tool batches) and use bounded catch-up waits of at most 30 seconds. Each Review has its own deadline and tool-call budget. Findings are deduplicated without merging distinct code identifiers; ordinary concerns observe a three-turn cooldown, while blockers bypass cooldown but not duplicate or per-Review limits.
58
+
59
+ Running work receives native steering. A blocker after normal interactive completion may receive a tracked corrective continuation within the configured budget; aborted, uncertain, deliberately interrupted, and headless-completed work is preserved without a hidden restart. Child corrections stay inside Minimal's owned operation. Headless root shutdown allows only a bounded final drain and never starts hidden corrective work.
60
+
61
+ Status reports effective settings, sources, review state, backlog, usage/cost, and the last error. Unknown cost is shown as unknown, never zero. Review failure pauses Advisor while leaving the observed agent running; changing configuration, branch, or session identity invalidates stale in-flight work.
62
+
63
+ Advisor is privileged extension code. Review inherited extensions and granted tools before installing it in a session with access to local files, credentials, or mutating APIs.
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@ian-pascoe/pi-advisor",
3
+ "version": "0.0.0",
4
+ "private": false,
5
+ "description": "Background review and attributed corrective advice for Pi agent sessions.",
6
+ "keywords": [
7
+ "advisor",
8
+ "pi",
9
+ "pi-extension",
10
+ "pi-package"
11
+ ],
12
+ "homepage": "https://github.com/ian-pascoe/pi-extensions/tree/main/packages/pi-advisor",
13
+ "bugs": {
14
+ "url": "https://github.com/ian-pascoe/pi-extensions/issues"
15
+ },
16
+ "license": "MIT",
17
+ "author": "Ian Pascoe <ian.g.pascoe@gmail.com>",
18
+ "repository": {
19
+ "type": "git",
20
+ "url": "git+https://github.com/ian-pascoe/pi-extensions.git",
21
+ "directory": "packages/pi-advisor"
22
+ },
23
+ "files": [
24
+ "src",
25
+ "skills",
26
+ "README.md",
27
+ "LICENSE"
28
+ ],
29
+ "type": "module",
30
+ "publishConfig": {
31
+ "access": "public",
32
+ "provenance": true
33
+ },
34
+ "scripts": {
35
+ "test": "vitest run --config ../../vitest.config.ts --root .",
36
+ "typecheck": "tsc --noEmit -p tsconfig.json"
37
+ },
38
+ "dependencies": {
39
+ "@ian-pascoe/pi-utils": "^0.2.0"
40
+ },
41
+ "devDependencies": {
42
+ "@earendil-works/pi-agent-core": "0.85.1",
43
+ "@earendil-works/pi-ai": "0.85.1",
44
+ "@earendil-works/pi-coding-agent": "0.85.1"
45
+ },
46
+ "peerDependencies": {
47
+ "@earendil-works/pi-agent-core": "*",
48
+ "@earendil-works/pi-ai": "*",
49
+ "@earendil-works/pi-coding-agent": "*",
50
+ "@earendil-works/pi-tui": "*",
51
+ "typebox": "*"
52
+ },
53
+ "engines": {
54
+ "node": ">=22.19.0"
55
+ },
56
+ "pi": {
57
+ "extensions": [
58
+ "./src/index.ts"
59
+ ],
60
+ "skills": [
61
+ "./skills"
62
+ ]
63
+ }
64
+ }
@@ -0,0 +1,20 @@
1
+ ---
2
+ name: pi-advisor
3
+ description: Diagnose Pi Advisor when reviews are missing, the Advisor is paused, settings are ineffective, backlog waits do not release, or corrective advice is not delivered safely.
4
+ license: MIT
5
+ ---
6
+
7
+ # Pi Advisor
8
+
9
+ Use this sequence for a live Advisor problem:
10
+
11
+ 1. Run `/advisor status`. Record the effective settings, each setting's source, review state, backlog, usage/cost, and last error. Treat unknown cost as unknown, not zero.
12
+ 2. If the state is disabled, check the selected session override, trusted-project settings, and global settings in that order. Advisor defaults to disabled. Use `/advisor on`, `/advisor off`, `/advisor inherit`, or `/advisor set <key> <JSON>` at the intended scope; use `/advisor prompt` for the native prompt editor. Confirm the selected branch after resume, fork, or tree navigation.
13
+ 3. If the state is paused, read the reported capability or review error. Correct the setting or unavailable runtime capability, then explicitly re-enable or reload as the diagnostic instructs. A pause leaves the observed agent running.
14
+ 4. For missing reviews, inspect backlog and catch-up configuration. Backlog counts completed model responses with their tool batches, including work under review. `off` never waits; a positive threshold waits only while backlog is at least that threshold, and each wait is capped at 30 seconds. A review has its own deadline and investigative-call limit.
15
+ 5. If Context Management is loaded, verify that all three private tools—`context_notes`, `context_history`, and `context_rollover`—are explicitly granted. Any missing grant pauses Advisor before review. These tools operate on the Advisor Session's private Notes, History, and Checkpoints; they never grant access to the observed session. Confirm native settlement and checkpoint completion rather than treating an early response or `agent_end` report as completion.
16
+ 6. For tool or CodeMode failures, compare the effective `allowedTools` list with the loaded registry. Missing names are reported and ignored. CodeMode-only exposure needs an explicitly compatible transport grant; Advisor does not add aliases, autogrant tools, or change exposure mode. A Tool Grant covers the tool's full native interface and is not a filesystem or operation sandbox.
17
+ 7. For stale, duplicated, or unsafe advice, check branch/session identity and configuration-generation changes. Advisor Sessions are separate persisted native sessions with fresh extension resources. Unsupported opaque inline/custom resources pause rather than being reused. Running work is steered through Pi's native boundary; blockers after normal interactive completion use only tracked, budgeted Corrective Turns. Deliberately interrupted, aborted, uncertain, and headless-completed work is preserved without restart. Child correction must finish inside Minimal's owned operation.
18
+ 8. On shutdown, allow only the bounded headless final drain. Verify that no hidden corrective turn starts after root completion and that native Advisor resources are aborted before disposal.
19
+
20
+ Finish when `/advisor status` shows the intended settings and a Review has settled without error: either an attributed finding is visible or Advisor remains silent with zero backlog. If a capability remains unsupported, report the exact diagnostic instead of bypassing native lifecycle or permission policy.
@@ -0,0 +1,58 @@
1
+ import type { AutocompleteItem } from "@earendil-works/pi-tui";
2
+ import {
3
+ advisorOptionKey,
4
+ advisorOptionKeys,
5
+ parseAdvisorOptions,
6
+ type AdvisorOptions,
7
+ } from "./advisor-settings.js";
8
+
9
+ /** Native command completion values replace the entire argument prefix. */
10
+ export function completeAdvisorCommandArguments(prefix: string): AutocompleteItem[] {
11
+ const candidates = ["on", "off", "status", "prompt", "inherit", "set"];
12
+ const keyPrefix = /^((?:set|inherit)\s+)\S*$/.exec(prefix)?.[1];
13
+ if (keyPrefix) candidates.push(...advisorOptionKeys.map((key) => `${keyPrefix}${key}`));
14
+ const scopePrefix = /^(.*\s+)(--\S*)?$/s.exec(prefix)?.[1];
15
+ if (scopePrefix) {
16
+ try {
17
+ const command = parseAdvisorCommand(scopePrefix);
18
+ if (command.action !== "status" && command.scope === "session")
19
+ candidates.push(`${scopePrefix}--global`, `${scopePrefix}--project`);
20
+ } catch {
21
+ // Incomplete commands and JSON values cannot accept a scope yet.
22
+ }
23
+ }
24
+ return candidates
25
+ .filter((value) => value.startsWith(prefix))
26
+ .map((value) => ({ value, label: value }));
27
+ }
28
+
29
+ const usage =
30
+ "Usage: /advisor [on|off|status|prompt|inherit [key]|set <key> <JSON>] [--global|--project]";
31
+
32
+ /** Parse one configuration change; validated patches cannot invent option keys. */
33
+ export function parseAdvisorCommand(input: string) {
34
+ const flag = /\s+--(global|project)$/.exec(input.trim());
35
+ const scope =
36
+ flag?.[1] === "global"
37
+ ? ("global" as const)
38
+ : flag?.[1] === "project"
39
+ ? ("project" as const)
40
+ : ("session" as const);
41
+ const text = (flag ? input.trim().slice(0, flag.index) : input.trim()) || "status";
42
+ if (text === "status") {
43
+ if (flag) throw new Error(usage);
44
+ return { action: "status" as const };
45
+ }
46
+ if (text === "prompt") return { action: "prompt" as const, scope };
47
+ if (text === "on" || text === "off") {
48
+ return { action: "set" as const, scope, patch: { enabled: text === "on" } };
49
+ }
50
+ const inherit = /^inherit(?:\s+(\S+))?$/.exec(text);
51
+ if (inherit) {
52
+ return { action: "inherit" as const, scope, key: advisorOptionKey(inherit[1] ?? "enabled") };
53
+ }
54
+ const set = /^set\s+(\S+)\s+([\s\S]+)$/.exec(text);
55
+ if (!set?.[1] || !set[2]) throw new Error(usage);
56
+ const patch: AdvisorOptions = parseAdvisorOptions({ [set[1]]: JSON.parse(set[2]) }, scope);
57
+ return { action: "set" as const, scope, patch };
58
+ }