@herbertgao/pi-extensions 2026.9.13 → 2026.9.15
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 +3 -3
- package/THIRD_PARTY_NOTICES.md +2 -2
- package/node_modules/@herbertgao/pi-bark/package.json +2 -2
- package/node_modules/@herbertgao/pi-cc-extensions/package.json +4 -4
- package/node_modules/@herbertgao/pi-subagents/CHANGELOG.md +6 -0
- package/node_modules/@herbertgao/pi-subagents/package.json +4 -4
- package/node_modules/@herbertgao/resume-from/package.json +2 -2
- package/node_modules/@herbertgao/sol-pi/package.json +5 -5
- package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts +2 -0
- package/node_modules/pi-jev-auto-mode/CHANGELOG.md +8 -0
- package/node_modules/pi-jev-auto-mode/README.md +7 -0
- package/node_modules/pi-jev-auto-mode/package.json +1 -1
- package/node_modules/pi-jev-auto-mode/src/extension.ts +21 -2
- package/node_modules/pi-jev-auto-mode/src/records.ts +68 -2
- package/node_modules/pi-jev-auto-mode/src/settings.ts +22 -0
- package/node_modules/pi-jev-auto-mode/src/ui.ts +10 -0
- package/node_modules/pi-mcp-adapter/CHANGELOG.md +26 -0
- package/node_modules/pi-mcp-adapter/README.md +39 -9
- package/node_modules/pi-mcp-adapter/cli.js +33 -22
- package/node_modules/pi-mcp-adapter/commands.ts +3 -3
- package/node_modules/pi-mcp-adapter/config.ts +9 -1
- package/node_modules/pi-mcp-adapter/dist/config.js +9 -1
- package/node_modules/pi-mcp-adapter/dist/config.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/jev-client.d.ts +1 -2
- package/node_modules/pi-mcp-adapter/dist/jev-client.js +59 -32
- package/node_modules/pi-mcp-adapter/dist/jev-client.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/jev-contracts.d.ts +1 -1
- package/node_modules/pi-mcp-adapter/dist/jev-key-store.d.ts +33 -4
- package/node_modules/pi-mcp-adapter/dist/jev-key-store.js +148 -28
- package/node_modules/pi-mcp-adapter/dist/jev-key-store.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/mcp-auth-flow.js +1 -2
- package/node_modules/pi-mcp-adapter/dist/mcp-auth-flow.js.map +1 -1
- package/node_modules/pi-mcp-adapter/dist/types.d.ts +7 -1
- package/node_modules/pi-mcp-adapter/dist/types.js.map +1 -1
- package/node_modules/pi-mcp-adapter/index.ts +51 -38
- package/node_modules/pi-mcp-adapter/jev-client.ts +58 -31
- package/node_modules/pi-mcp-adapter/jev-contracts.ts +2 -2
- package/node_modules/pi-mcp-adapter/jev-key-store.ts +144 -31
- package/node_modules/pi-mcp-adapter/mcp-auth-flow.ts +1 -2
- package/node_modules/pi-mcp-adapter/mcp-code.ts +6 -6
- package/node_modules/pi-mcp-adapter/package.json +5 -5
- package/node_modules/pi-mcp-adapter/semantic-search.ts +3 -3
- package/node_modules/pi-mcp-adapter/types.ts +7 -1
- package/node_modules/pi-multi-account/CHANGELOG.md +12 -0
- package/node_modules/pi-multi-account/README.md +21 -6
- package/node_modules/pi-multi-account/index.ts +295 -41
- package/node_modules/pi-multi-account/package.json +3 -3
- package/node_modules/pi-typesafe/dist/backends.d.ts +10 -0
- package/node_modules/pi-typesafe/dist/backends.js +26 -0
- package/node_modules/pi-typesafe/dist/client.d.ts +1 -1
- package/node_modules/pi-typesafe/dist/client.js +10 -6
- package/node_modules/pi-typesafe/dist/errors.d.ts +10 -2
- package/node_modules/pi-typesafe/dist/errors.js +28 -7
- package/node_modules/pi-typesafe/dist/extension.js +2 -1
- package/node_modules/pi-typesafe/package.json +4 -4
- package/node_modules/pi-web-access/CHANGELOG.md +22 -0
- package/node_modules/pi-web-access/README.md +21 -8
- package/node_modules/pi-web-access/baizhi.ts +124 -0
- package/node_modules/pi-web-access/crawl4ai.ts +2 -10
- package/node_modules/pi-web-access/curator-page.ts +3 -1
- package/node_modules/pi-web-access/curator-server.ts +1 -0
- package/node_modules/pi-web-access/dist/index.js +540 -220
- package/node_modules/pi-web-access/firecrawl.ts +2 -10
- package/node_modules/pi-web-access/gemini-search.ts +5 -10
- package/node_modules/pi-web-access/index.ts +134 -23
- package/node_modules/pi-web-access/package.json +5 -1
- package/node_modules/pi-web-access/storage.ts +1 -0
- package/node_modules/pi-web-access/tool-activation.ts +134 -0
- package/node_modules/pi-web-access/utils.ts +9 -1
- package/package.json +14 -14
package/README.md
CHANGED
|
@@ -28,9 +28,9 @@ The package bundles 6 active `@herbertgao/*` child packages—`pi-bark`, `pi-cc-
|
|
|
28
28
|
- `@tifan/pi-rename@0.6.0`
|
|
29
29
|
- `pi-mcp-adapter@2.31.0`
|
|
30
30
|
- `pi-typesafe@0.7.1`
|
|
31
|
-
- `pi-multi-account@1.23.
|
|
31
|
+
- `pi-multi-account@1.23.2`
|
|
32
32
|
- `pi-footer@0.5.1`
|
|
33
|
-
- `pi-jev-auto-mode@0.
|
|
33
|
+
- `pi-jev-auto-mode@0.5.0`
|
|
34
34
|
- `pi-lens@4.2.1`
|
|
35
35
|
- `pi-web-access@0.27.0`
|
|
36
36
|
- `remote-pi@0.7.0`
|
|
@@ -43,7 +43,7 @@ Pi loads their extensions and skills through `node_modules/` paths inside one pa
|
|
|
43
43
|
|
|
44
44
|
`@narumitw/pi-caffeinate@0.49.7` uses the host platform's sleep inhibitor during each Pi agent run. On macOS, `/caffeinate sleep` keeps the system awake while allowing the display to sleep; `/caffeinate display` also keeps the display awake. It releases the inhibitor when the run or session ends.
|
|
45
45
|
|
|
46
|
-
`pi-jev-auto-mode@0.
|
|
46
|
+
`pi-jev-auto-mode@0.5.0` adds fail-closed Jev safety gates for shell commands and file changes. `pi-typesafe@0.7.1` adds the `/typesafe` command and `typesafe_evaluate` tool for explicit structured decisions; both use the TypeSafe API after login.
|
|
47
47
|
|
|
48
48
|
`@herbertgao/resume-from@0.2.0` keeps Claude Code sessions associated with their original repository when the active transcript later moves into a nested cwd. `@herbertgao/sol-pi@0.1.0` adds opt-in Action Fusion, ObservationPack, Evidence-Preserving Reducer, and Online Context Compact; see its [configuration guide](../sol-pi/docs/configuration.md). `pi-lens@4.2.1` expands language routing and bounds retained diagnostic facts across multi-root sessions. `pi-web-access@0.27.0` adds configurable fetch deadlines and answer models plus isolated GitHub clone runtimes. Preferred Thinking 1.0.1 preserves an explicit subagent `--thinking` choice. Deprecated `@tifan/pi-titlebar-spinner` is no longer bundled; Rename remains the single owner of Herdr tab naming.
|
|
49
49
|
|
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -137,7 +137,7 @@ THE SOFTWARE.
|
|
|
137
137
|
|
|
138
138
|
## `pi-jev-auto-mode`
|
|
139
139
|
|
|
140
|
-
The aggregate bundles [`pi-jev-auto-mode`](https://github.com/jomatsu/pi-jev-auto-mode) version 0.
|
|
140
|
+
The aggregate bundles [`pi-jev-auto-mode`](https://github.com/jomatsu/pi-jev-auto-mode) version 0.5.0 under its original MIT license:
|
|
141
141
|
|
|
142
142
|
MIT License
|
|
143
143
|
|
|
@@ -163,7 +163,7 @@ THE SOFTWARE.
|
|
|
163
163
|
|
|
164
164
|
## `pi-multi-account`
|
|
165
165
|
|
|
166
|
-
The aggregate bundles the MIT-licensed [`pi-multi-account`](https://github.com/Sarrius/pi-multi-account) package version 1.23.
|
|
166
|
+
The aggregate bundles the MIT-licensed [`pi-multi-account`](https://github.com/Sarrius/pi-multi-account) package version 1.23.2 under its original attribution:
|
|
167
167
|
|
|
168
168
|
MIT License
|
|
169
169
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-bark",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.3",
|
|
4
4
|
"description": "Send Bark notifications when Pi finishes or needs user input.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"bark",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"typescript": "^5.9.3"
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
42
|
+
"@earendil-works/pi-coding-agent": "^0.87.1"
|
|
43
43
|
},
|
|
44
44
|
"engines": {
|
|
45
45
|
"node": ">=24"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-cc-extensions",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "A Pi productivity suite with Claude Code-style UI, context inspection, and agent/session references",
|
|
6
6
|
"type": "module",
|
|
@@ -51,9 +51,9 @@
|
|
|
51
51
|
"jiti": "^2.7.0"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@earendil-works/pi-ai": "^0.
|
|
55
|
-
"@earendil-works/pi-coding-agent": "^0.
|
|
56
|
-
"@earendil-works/pi-tui": "^0.
|
|
54
|
+
"@earendil-works/pi-ai": "^0.87.1",
|
|
55
|
+
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
56
|
+
"@earendil-works/pi-tui": "^0.87.1"
|
|
57
57
|
},
|
|
58
58
|
"engines": {
|
|
59
59
|
"node": ">=24"
|
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.18.3
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#232](https://github.com/HerbertGao/pi-extensions/pull/232) [`9c3c40f`](https://github.com/HerbertGao/pi-extensions/commit/9c3c40f113c62437f76d300042fc59fbf15954c0) Thanks [@HerbertGao](https://github.com/HerbertGao)! - Require the unified Pi 0.87.1 dependency line across published packages.
|
|
8
|
+
|
|
3
9
|
## 0.18.2
|
|
4
10
|
|
|
5
11
|
### Patch Changes
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/pi-subagents",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"description": "Claude Code-style autonomous subagents and workflow orchestration for Pi, with HerbertGao-maintained UI extensions.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent",
|
|
@@ -54,9 +54,9 @@
|
|
|
54
54
|
"@vitest/coverage-istanbul": "^4.1.10"
|
|
55
55
|
},
|
|
56
56
|
"peerDependencies": {
|
|
57
|
-
"@earendil-works/pi-ai": "
|
|
58
|
-
"@earendil-works/pi-coding-agent": "
|
|
59
|
-
"@earendil-works/pi-tui": "
|
|
57
|
+
"@earendil-works/pi-ai": "^0.87.1",
|
|
58
|
+
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
59
|
+
"@earendil-works/pi-tui": "^0.87.1"
|
|
60
60
|
},
|
|
61
61
|
"engines": {
|
|
62
62
|
"node": ">=24"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/resume-from",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3",
|
|
4
4
|
"description": "Continue a coding session in a different agent, or a different profile.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"vitest": "^4.1.10"
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
|
-
"@earendil-works/pi-tui": "^0.
|
|
66
|
+
"@earendil-works/pi-tui": "^0.87.1",
|
|
67
67
|
"gpt-tokenizer": "^3.4.0"
|
|
68
68
|
},
|
|
69
69
|
"pi": {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@herbertgao/sol-pi",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.2",
|
|
4
4
|
"description": "Token-efficient context and tool extensions for Pi, maintained from NVlabs/SoL-Pi.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -47,10 +47,10 @@
|
|
|
47
47
|
"check": "npm run typecheck && npm test && npm pack --dry-run"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
|
-
"@earendil-works/pi-agent-core": "
|
|
51
|
-
"@earendil-works/pi-ai": "
|
|
52
|
-
"@earendil-works/pi-coding-agent": "
|
|
53
|
-
"@earendil-works/pi-tui": "
|
|
50
|
+
"@earendil-works/pi-agent-core": "^0.87.1",
|
|
51
|
+
"@earendil-works/pi-ai": "^0.87.1",
|
|
52
|
+
"@earendil-works/pi-coding-agent": "^0.87.1",
|
|
53
|
+
"@earendil-works/pi-tui": "^0.87.1",
|
|
54
54
|
"typebox": ">=1.3.7"
|
|
55
55
|
},
|
|
56
56
|
"devDependencies": {
|
package/node_modules/@herbertgao/sol-pi/src/sol-pi/extensions/online-context-compact/extension.ts
CHANGED
|
@@ -450,6 +450,8 @@ export function createOnlineContextCompactExtension(options: OnlineContextCompac
|
|
|
450
450
|
continuation.resolve();
|
|
451
451
|
throw error;
|
|
452
452
|
}
|
|
453
|
+
// triggerTurn starts on the next event-loop turn; checking immediately is racy.
|
|
454
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 0));
|
|
453
455
|
if (context.isIdle() && nextContinuation === continuation) {
|
|
454
456
|
nextContinuation = undefined;
|
|
455
457
|
continuation.resolve();
|
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.5.0 - 2026-09-24
|
|
4
|
+
|
|
5
|
+
- **Decision records are compact by default.** An approval is drawn as one line — status, tool,
|
|
6
|
+
latency, and the command — and a block as two, keeping the rationale. Each record used to take
|
|
7
|
+
five padded blocks, so a long session was mostly gate records. `/jev-auto-mode display full`
|
|
8
|
+
(or `"display": "full"`) restores the previous view, and the expanded view shows every detail
|
|
9
|
+
in either mode.
|
|
10
|
+
|
|
3
11
|
## 0.4.1 - 2026-09-18
|
|
4
12
|
|
|
5
13
|
- **An unclear answer passes by default.** `uncertain` defaulted to `deny`, which meant a
|
|
@@ -113,8 +113,14 @@ Packages are discovered in the [package gallery](https://pi.dev/packages) throug
|
|
|
113
113
|
/jev-auto-mode uncertain show what the middle band resolves to
|
|
114
114
|
/jev-auto-mode uncertain deny|ask|allow
|
|
115
115
|
/jev-auto-mode scope all|matched how far the semantic layer reaches
|
|
116
|
+
/jev-auto-mode display full|compact how decision records are drawn
|
|
116
117
|
```
|
|
117
118
|
|
|
119
|
+
Each decision leaves a record in the transcript. `display: "compact"` (the default) folds an
|
|
120
|
+
approval into one line and a block into two (the rationale stays, because a block is something
|
|
121
|
+
to act on). `display: "full"` shows the heading, the engine line, the command, the reasons, and
|
|
122
|
+
the rationale. The expanded view shows every detail in either mode.
|
|
123
|
+
|
|
118
124
|
```
|
|
119
125
|
pi --jev-auto-mode start with auto mode enabled
|
|
120
126
|
```
|
|
@@ -195,6 +201,7 @@ Policy notes: `$PI_CODING_AGENT_DIR/jev-auto-mode-policy.md`.
|
|
|
195
201
|
"maxStateCharacters": 120000,
|
|
196
202
|
"uncertain": "deny",
|
|
197
203
|
"gateScope": "all",
|
|
204
|
+
"display": "compact",
|
|
198
205
|
"thresholds": {}
|
|
199
206
|
}
|
|
200
207
|
```
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-jev-auto-mode",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Jev (TypeSafe System One) backed auto mode for the Pi coding agent: semantically auto-approves bash, write, and edit tool calls and fails closed when a decision cannot be made.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi-package",
|
|
@@ -55,6 +55,7 @@ import {
|
|
|
55
55
|
import {
|
|
56
56
|
DEFAULT_SETTINGS,
|
|
57
57
|
JevAutoModeStore,
|
|
58
|
+
isDisplayMode,
|
|
58
59
|
isGateScope,
|
|
59
60
|
isUncertainAction,
|
|
60
61
|
parseThreshold,
|
|
@@ -64,6 +65,7 @@ import {
|
|
|
64
65
|
import {
|
|
65
66
|
buildConfirmationDialog,
|
|
66
67
|
describeSettings,
|
|
68
|
+
DISPLAY_EXPLANATION,
|
|
67
69
|
GATE_SCOPE_EXPLANATION,
|
|
68
70
|
UNCERTAIN_EXPLANATION,
|
|
69
71
|
formatRuleTable,
|
|
@@ -571,7 +573,7 @@ export function register(pi: ExtensionAPI, options: RegisterOptions = {}): void
|
|
|
571
573
|
default: false,
|
|
572
574
|
});
|
|
573
575
|
|
|
574
|
-
registerDecisionEntryRenderer(pi);
|
|
576
|
+
registerDecisionEntryRenderer(pi, () => state.settings.display);
|
|
575
577
|
|
|
576
578
|
pi.registerCommand(AUTO_MODE_COMMAND, {
|
|
577
579
|
description: "Show or change the Jev auto mode settings",
|
|
@@ -579,7 +581,7 @@ export function register(pi: ExtensionAPI, options: RegisterOptions = {}): void
|
|
|
579
581
|
const value = String(argumentPrefix ?? "");
|
|
580
582
|
const tokens = value.split(/\s+/).filter(Boolean);
|
|
581
583
|
if (tokens.length === 0) {
|
|
582
|
-
return ["status", "on", "off", "policy", "threshold", "scope", "uncertain", "login", "logout"].map((item) => ({
|
|
584
|
+
return ["status", "on", "off", "policy", "threshold", "scope", "uncertain", "display", "login", "logout"].map((item) => ({
|
|
583
585
|
value: item,
|
|
584
586
|
label: item,
|
|
585
587
|
}));
|
|
@@ -756,6 +758,23 @@ export function register(pi: ExtensionAPI, options: RegisterOptions = {}): void
|
|
|
756
758
|
return;
|
|
757
759
|
}
|
|
758
760
|
|
|
761
|
+
if (value.startsWith("display")) {
|
|
762
|
+
const argument = value.slice("display".length).trim();
|
|
763
|
+
if (argument === "") {
|
|
764
|
+
ctx.ui.notify(`display: ${state.settings.display}\n\n${DISPLAY_EXPLANATION}`, "info");
|
|
765
|
+
return;
|
|
766
|
+
}
|
|
767
|
+
if (!isDisplayMode(argument)) {
|
|
768
|
+
ctx.ui.notify(`Expected one of full, compact.\n\n${DISPLAY_EXPLANATION}`, "error");
|
|
769
|
+
return;
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
state.settings = { ...state.settings, display: argument };
|
|
773
|
+
await save(gateContext);
|
|
774
|
+
ctx.ui.notify(`decision records now display as: ${argument}`, "info");
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
|
|
759
778
|
if (value.startsWith("uncertain")) {
|
|
760
779
|
const argument = value.slice("uncertain".length).trim();
|
|
761
780
|
if (argument === "") {
|
|
@@ -6,10 +6,11 @@
|
|
|
6
6
|
* recorded rationale should not become ammunition for the next tool call.
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
|
-
import { Box, Text } from "@earendil-works/pi-tui";
|
|
9
|
+
import { Box, Text, truncateToWidth, type Component } from "@earendil-works/pi-tui";
|
|
10
10
|
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
11
11
|
import type { ConditionReport, DecisionSource } from "./decide.ts";
|
|
12
12
|
import { formatThreshold } from "./jev/decide.ts";
|
|
13
|
+
import type { DisplayMode } from "./settings.ts";
|
|
13
14
|
|
|
14
15
|
export const DECISION_ENTRY_TYPE = "jev-auto-mode-decision";
|
|
15
16
|
|
|
@@ -85,12 +86,77 @@ export function formatConditionLines(record: DecisionRecord): string[] {
|
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
|
|
88
|
-
|
|
89
|
+
/** Collapse whitespace so a multi-line command reads as one line. */
|
|
90
|
+
function oneLine(text: string): string {
|
|
91
|
+
return text.replace(/\s+/g, " ").trim();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface CompactDecisionLines {
|
|
95
|
+
/** `🛡 jev allowed · bash · 299ms · <command>`: everything an approval needs. */
|
|
96
|
+
readonly headline: string;
|
|
97
|
+
/**
|
|
98
|
+
* The rationale, only for a call that did not run. An approval does not need its
|
|
99
|
+
* reasoning on screen; a block does, because the user has to act on it.
|
|
100
|
+
*/
|
|
101
|
+
readonly detail?: string;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* The compact view: one line for an approval, two for a block.
|
|
106
|
+
*
|
|
107
|
+
* Width is applied at render time. This only decides what the lines say.
|
|
108
|
+
*/
|
|
109
|
+
export function formatCompactLines(record: DecisionRecord): CompactDecisionLines {
|
|
110
|
+
const approved = record.status === "allowed" || record.status === "confirmed";
|
|
111
|
+
const parts = [`${approved ? "🛡" : "⛔"} jev ${STATUS_LABEL[record.status]}`, record.tool];
|
|
112
|
+
if (!approved) parts.push(`via ${record.source}`);
|
|
113
|
+
if (typeof record.latencyMs === "number") parts.push(`${Math.round(record.latencyMs)}ms`);
|
|
114
|
+
const summary = oneLine(record.summary);
|
|
115
|
+
if (summary.length > 0) parts.push(summary);
|
|
116
|
+
const headline = parts.join(" · ");
|
|
117
|
+
if (approved) return { headline };
|
|
118
|
+
return { headline, detail: oneLine(record.rationale) };
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/** A single line clipped to the viewport instead of wrapped. */
|
|
122
|
+
class ClippedLine implements Component {
|
|
123
|
+
private readonly text: string;
|
|
124
|
+
|
|
125
|
+
constructor(text: string) {
|
|
126
|
+
this.text = text;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
render(width: number): string[] {
|
|
130
|
+
return [truncateToWidth(this.text, Math.max(1, width))];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
invalidate(): void {}
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export type DisplayModeSource = () => DisplayMode;
|
|
137
|
+
|
|
138
|
+
export function registerDecisionEntryRenderer(
|
|
139
|
+
pi: Pick<ExtensionAPI, "registerEntryRenderer">,
|
|
140
|
+
displayMode: DisplayModeSource = () => "compact",
|
|
141
|
+
): void {
|
|
89
142
|
pi.registerEntryRenderer<DecisionRecord>(DECISION_ENTRY_TYPE, (entry, options, theme) => {
|
|
90
143
|
const record = entry.data;
|
|
91
144
|
if (!record) return undefined;
|
|
92
145
|
|
|
93
146
|
const approved = record.status === "allowed" || record.status === "confirmed";
|
|
147
|
+
|
|
148
|
+
// The expanded view is the place to read a decision in full, so it ignores the
|
|
149
|
+
// compact setting.
|
|
150
|
+
if (displayMode() === "compact" && !options.expanded) {
|
|
151
|
+
const lines = formatCompactLines(record);
|
|
152
|
+
const box = new Box(1, 0, (text) => theme.bg("customMessageBg", text));
|
|
153
|
+
box.addChild(new ClippedLine(theme.fg(approved ? "muted" : "error", lines.headline)));
|
|
154
|
+
if (lines.detail !== undefined) {
|
|
155
|
+
box.addChild(new ClippedLine(theme.fg("dim", `rationale: ${lines.detail}`)));
|
|
156
|
+
}
|
|
157
|
+
return box;
|
|
158
|
+
}
|
|
159
|
+
|
|
94
160
|
const icon = approved ? "🛡" : "⛔";
|
|
95
161
|
const heading = `${icon} ${theme.bold("jev auto mode")} ${theme.fg(
|
|
96
162
|
approved ? "success" : "error",
|
|
@@ -45,6 +45,23 @@ export interface JevAutoModeSettings {
|
|
|
45
45
|
* visible in `/jev-auto-mode threshold` instead of silently resetting the rule.
|
|
46
46
|
*/
|
|
47
47
|
readonly thresholds: Readonly<Record<string, number>>;
|
|
48
|
+
/**
|
|
49
|
+
* How decision records are drawn in the transcript.
|
|
50
|
+
*
|
|
51
|
+
* `compact` (the default) folds an approval into one line and a block into two, so
|
|
52
|
+
* a long session is not dominated by gate records. `full` shows the heading, the
|
|
53
|
+
* engine line, the command, the reasons, and the rationale. The expanded view (the tool
|
|
54
|
+
* expansion key) always shows every detail, whichever mode is set.
|
|
55
|
+
*/
|
|
56
|
+
readonly display: DisplayMode;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export type DisplayMode = "full" | "compact";
|
|
60
|
+
|
|
61
|
+
export const DISPLAY_MODES: readonly DisplayMode[] = ["full", "compact"];
|
|
62
|
+
|
|
63
|
+
export function isDisplayMode(value: unknown): value is DisplayMode {
|
|
64
|
+
return typeof value === "string" && DISPLAY_MODES.includes(value as DisplayMode);
|
|
48
65
|
}
|
|
49
66
|
|
|
50
67
|
export type SettingsScope = "global" | "project";
|
|
@@ -90,6 +107,7 @@ export const DEFAULT_SETTINGS: JevAutoModeSettings = {
|
|
|
90
107
|
uncertain: "allow",
|
|
91
108
|
gateScope: "all",
|
|
92
109
|
thresholds: {},
|
|
110
|
+
display: "compact",
|
|
93
111
|
};
|
|
94
112
|
|
|
95
113
|
const MAX_PATTERN_ENTRIES = 200;
|
|
@@ -193,6 +211,10 @@ export function parseSettingsPatch(value: unknown): SettingsPatch {
|
|
|
193
211
|
patch.gateScope = record.gateScope;
|
|
194
212
|
}
|
|
195
213
|
|
|
214
|
+
if (record.display !== undefined && isDisplayMode(record.display)) {
|
|
215
|
+
patch.display = record.display;
|
|
216
|
+
}
|
|
217
|
+
|
|
196
218
|
const safeCommands = record.safeCommands === undefined ? undefined : readStringArray(record.safeCommands);
|
|
197
219
|
if (safeCommands !== undefined) patch.safeCommands = safeCommands;
|
|
198
220
|
|
|
@@ -44,6 +44,7 @@ export function describeSettings(settings: JevAutoModeSettings, scope: SettingsS
|
|
|
44
44
|
`max state characters: ${settings.maxStateCharacters}`,
|
|
45
45
|
`uncertain band: ${settings.uncertain}`,
|
|
46
46
|
`gate scope: ${settings.gateScope}`,
|
|
47
|
+
`display: ${settings.display}`,
|
|
47
48
|
].join("\n");
|
|
48
49
|
}
|
|
49
50
|
|
|
@@ -149,6 +150,15 @@ export const USAGE_TEXT = [
|
|
|
149
150
|
" /jev-auto-mode uncertain show what the middle band resolves to",
|
|
150
151
|
" /jev-auto-mode uncertain deny|ask|allow",
|
|
151
152
|
" /jev-auto-mode scope all|matched which calls reach Jev",
|
|
153
|
+
" /jev-auto-mode display full|compact how decision records are drawn",
|
|
154
|
+
].join("\n");
|
|
155
|
+
|
|
156
|
+
export const DISPLAY_EXPLANATION = [
|
|
157
|
+
"How decision records are drawn in the transcript.",
|
|
158
|
+
" compact - one line for an approval, two for a block (with the rationale) (default).",
|
|
159
|
+
" full - heading, engine line, command, reasons, and rationale.",
|
|
160
|
+
"The expanded view always shows every detail. New records use the mode at once;",
|
|
161
|
+
"records already on screen switch when Pi redraws them (e.g. toggling expansion).",
|
|
152
162
|
].join("\n");
|
|
153
163
|
|
|
154
164
|
export const GATE_SCOPE_EXPLANATION = [
|
|
@@ -7,6 +7,32 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [2.37.0] - 2026-09-23
|
|
11
|
+
|
|
12
|
+
### Highlights
|
|
13
|
+
|
|
14
|
+
- Use Jev semantic search with other System One providers, such as OpenCode Zen, Command Code, or OpenRouter, by setting `SYSTEMONE_ENDPOINT`.
|
|
15
|
+
- Stop agents from installing new MCP servers with `settings.allowInstall: false`.
|
|
16
|
+
- Turn off resource tools for every server with one `settings.exposeResources: false` setting.
|
|
17
|
+
- Start Pi without waiting on MCP servers even when cached tool metadata is missing, with `settings.deferWithMissingMetadata`.
|
|
18
|
+
|
|
19
|
+
### Added
|
|
20
|
+
|
|
21
|
+
- Jev can send System One requests to any HTTPS provider endpoint set in `SYSTEMONE_ENDPOINT`. TypeSafe stays the default. API keys are stored per endpoint, and an invalid endpoint turns Jev off instead of quietly falling back to TypeSafe. Thanks to [@jagaliano](https://github.com/jagaliano) for [PR #645](https://github.com/nicobailon/pi-mcp-adapter/pull/645).
|
|
22
|
+
- `settings.deferWithMissingMetadata: true` lets Pi start without connecting to MCP servers even when their cached metadata is missing or out of date. Those servers show no tools until the first MCP call loads them. Thanks to [@j62268781-alt](https://github.com/j62268781-alt) for [#641](https://github.com/nicobailon/pi-mcp-adapter/issues/641).
|
|
23
|
+
- `settings.allowInstall: false` blocks agents from installing remote MCP servers with `mcp({ action: "install" })`, for headless or locked-down setups. Thanks to [@gastmaier](https://github.com/gastmaier) for [#638](https://github.com/nicobailon/pi-mcp-adapter/issues/638).
|
|
24
|
+
- `settings.exposeResources: false` hides resource tools for every server. A server's own `exposeResources` setting still wins. Thanks to [@rakesh-vs](https://github.com/rakesh-vs) for [PR #636](https://github.com/nicobailon/pi-mcp-adapter/pull/636).
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- The Jev key command is now `pi-mcp-adapter key set systemone`, and the environment variable is `SYSTEMONE_API_KEY`. The old `key set typesafe` command still works, and `TYPESAFE_API_KEY` still works with the default TypeSafe endpoint.
|
|
29
|
+
- Supports Pi 0.87.
|
|
30
|
+
|
|
31
|
+
### Fixed
|
|
32
|
+
|
|
33
|
+
- `getMcpOAuthTokensForUrl` no longer returns an expired access token when no refresh token is stored, so other extensions see a signed-out server instead of sending a dead token. Thanks to [@benjaminsirb](https://github.com/benjaminsirb) for [#644](https://github.com/nicobailon/pi-mcp-adapter/issues/644).
|
|
34
|
+
- Tools in `directTools: "search"` mode now stay inactive until a search selects them, even if another extension turns them back on. Tools a search activates stay on until the session ends. Thanks to [@VoidInTheShell](https://github.com/VoidInTheShell) for [PR #640](https://github.com/nicobailon/pi-mcp-adapter/pull/640).
|
|
35
|
+
|
|
10
36
|
## [2.36.0] - 2026-09-21
|
|
11
37
|
|
|
12
38
|
### Highlights
|
|
@@ -394,7 +394,7 @@ Secret values in `headers`, `bearerToken`, `oauth.clientSecret`, and stdio `env`
|
|
|
394
394
|
|
|
395
395
|
For local desktop bearer tokens, `bearerTokenStore: true` can opt in to the adapter-owned credential-store namespace. It never falls back to plaintext if the store is unavailable, if the stored record is malformed, or if the stored URL differs from the effective server URL. Literal tokens, command tokens, and environment tokens keep precedence so existing configs do not change. Create or rotate a stored token with `pi-mcp-adapter token set <server>` (masked prompt on a terminal, or piped stdin such as `security find-generic-password -s my-token -w | pi-mcp-adapter token set <server>`); the record binds to the effective configured URL at write time. Token commands need Node 22.18+.
|
|
396
396
|
|
|
397
|
-
On Linux, bearer-token and
|
|
397
|
+
On Linux, bearer-token and System One key storage also recover automatically when a native operation fails with `KeyRevoked`, including wrapped errors from a revoked inherited session keyring. Each failed read/write/remove is retried once through `keyctl session - <current runtime> <packaged helper>`, with a 10-second timeout and no plaintext fallback. This requires `keyctl` on `PATH` and a working credential store in the fresh session; other storage errors still fail closed. Set `PI_MCP_ADAPTER_DISABLE_KEYRING_RECOVERY=1` to disable this recovery. Normal Pi and token CLI launches need no special wrapper.
|
|
398
398
|
|
|
399
399
|
### Shared MCP processes with rmcp-mux
|
|
400
400
|
|
|
@@ -422,6 +422,8 @@ mcp({ action: "install", url: "https://example.com/mcp" })
|
|
|
422
422
|
|
|
423
423
|
Install validates and connects the endpoint. New entries use a name derived from the hostname and are saved to Pi's global MCP config; existing URL entries are reused without rewriting. Pass `server` to choose a name or `target: "project"` to save to the project's `.mcp.json`. Unsafe URLs, name collisions, and failed connections are not persisted.
|
|
424
424
|
|
|
425
|
+
Set `settings.allowInstall` to `false` in an MCP config file (`mcp.json` or `.mcp.json`, not Pi's `settings.json`) to block `mcp({ action: "install" })` for constrained or headless agents. Connect, search, tool calls, authentication, runtime registration, and interactive setup are unaffected.
|
|
426
|
+
|
|
425
427
|
In exclusive config mode, a project target must be the active config path; otherwise use the global target. URL install cannot promote runtime-registered servers: save their complete definitions manually so required headers and transport/auth settings are retained.
|
|
426
428
|
|
|
427
429
|
Public servers are ready immediately. For OAuth servers, the same action opens the authorization page and watches a reachable loopback callback. After the user grants consent, an `mcp-oauth-status` message returns the agent to connect the server and verify its discovered tools. Remote/headless callbacks retain the manual completion fallback below.
|
|
@@ -469,8 +471,10 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
|
|
|
469
471
|
{
|
|
470
472
|
"settings": {
|
|
471
473
|
"toolPrefix": "server",
|
|
474
|
+
"allowInstall": false,
|
|
472
475
|
"idleTimeout": 10,
|
|
473
476
|
"requestTimeoutMs": 30000,
|
|
477
|
+
"deferWithMissingMetadata": false,
|
|
474
478
|
"showStatusIcon": true,
|
|
475
479
|
"mcpFooterStatus": "full",
|
|
476
480
|
"toolResultRendering": "compact",
|
|
@@ -494,8 +498,10 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
|
|
|
494
498
|
| Setting | Description |
|
|
495
499
|
|---------|-------------|
|
|
496
500
|
| `toolPrefix` | `"server"` (default), `"short"` (strips `-mcp` suffix), `"none"`, or `"mcp"` (prefixes with `mcp__`, using server-mode normalization). Per-server `toolPrefix` overrides this for that server. |
|
|
501
|
+
| `allowInstall` | Allow URL installation through the `mcp` tool (default: `true`). Set to `false` to block it. |
|
|
497
502
|
| `idleTimeout` | Global idle timeout in minutes (default: 10, 0 to disable) |
|
|
498
503
|
| `requestTimeoutMs` | Global request timeout in milliseconds for live MCP calls (if omitted or `<= 0`, the MCP SDK default timeout is used) |
|
|
504
|
+
| `deferWithMissingMetadata` | Allow lazy startup to defer when persisted metadata is missing or invalid (default: `false`). See [Direct Tools](#direct-tools) for the startup tradeoff. |
|
|
499
505
|
| `showStatusIcon` | Show the plug icon in MCP status and connection text (default: `true`). Set to `false` for plain `MCP: ...` text. |
|
|
500
506
|
| `mcpFooterStatus` | MCP footer verbosity: `"full"` (default), `"compact"` for `MCP connected/enabled`, or `"off"` to clear the persistent footer status. `/mcp status` remains available. |
|
|
501
507
|
| `toolResultRendering` | MCP tool result row style: `"compact"` (default) uses self-rendered rows, or `"boxed"` restores the legacy Pi boxed tool row. |
|
|
@@ -515,7 +521,8 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
|
|
|
515
521
|
| `warnOnLargeDirectTools` | Show the advisory when 75 or more direct tools resolve (default: `true`). Set to `false` to suppress only this advisory. |
|
|
516
522
|
| `freezeDirectTools` | Keep direct-tool registration stable after the initial sync so metadata updates and explicit reconnects do not rebuild the system prompt. Proxy/search/cache metadata still refreshes. Default: false. |
|
|
517
523
|
| `scriptMode` | Register the MCP-only `mcpScript` plain-JavaScript tool (default: true). Set to `false` to hide it. |
|
|
518
|
-
| `
|
|
524
|
+
| `exposeResources` | Expose MCP resources as tools (default: `true`). Set to `false` to disable globally across all servers. Per-server `exposeResources` overrides this. |
|
|
525
|
+
| `jev` | Optional System One Jev settings. A valid System One key enables semantic search across every enabled MCP server by default; `semanticSearch: false` disables it. `scriptEvaluation` remains disabled by default and requires an `allowedServers` source allowlist when enabled. `jev: false` disables both. Run `/mcp jev setup` for guided configuration. |
|
|
519
526
|
| `disableProxyTool` | Hide the `mcp` proxy tool once configured direct tools are fully available from cache. Ignored while any server uses `directTools: "search"`, whose tools are registered inactive and can only be activated through `mcp({ search })`. |
|
|
520
527
|
| `autoAuth` | Auto-run OAuth on `connect`/tool calls when a server needs auth, then retry once (default: false). |
|
|
521
528
|
| `sampling` | Allow MCP servers to sample through Pi models, honoring `modelPreferences.hints` before current/default fallback (default: true when UI approval is available). |
|
|
@@ -524,7 +531,7 @@ When any enabled server uses `eager` or `keep-alive`, initialization also starts
|
|
|
524
531
|
| `outputGuard` | Guard oversized MCP output: `true` (default), `false`, or `{ maxBytes, maxLines, detailsMaxBytes }`. See [Output Guard](#output-guard). |
|
|
525
532
|
| `trace` | Opt-in metadata-only protocol tracing. Set `{ enabled: true }` globally or `trace: true` on a server. The per-session JSONL file defaults to `.pi/mcp-traces/`; `file`, `maxBytes` (default 262144), and `maxEvents` (default 10000) can be set. Raw MCP payloads, prompts, tool arguments/results, auth data, and URLs are never persisted. |
|
|
526
533
|
|
|
527
|
-
Per-server `idleTimeout`, `requestTimeoutMs`, and `
|
|
534
|
+
Per-server `idleTimeout`, `requestTimeoutMs`, `approveTools`, and `exposeResources` override the global settings. `debug` remains stderr display and is unrelated to protocol tracing.
|
|
528
535
|
|
|
529
536
|
### Tool Approval
|
|
530
537
|
|
|
@@ -592,7 +599,7 @@ Set `"outputGuard": false` — or the env kill switch `MCP_OUTPUT_GUARD=0` — t
|
|
|
592
599
|
|
|
593
600
|
#### Jev semantic search and opt-in script evaluation
|
|
594
601
|
|
|
595
|
-
A valid
|
|
602
|
+
A valid System One key makes semantic search available across every enabled MCP server; it does not run Jev searches automatically. A search uses Jev only when `searchMode: "semantic"` is explicitly requested. Jev ranks matching tools but never executes them. Script evaluation remains disabled until `scriptEvaluation: true` is configured. Requests use the pinned model from `settings.jev.model` (`jev-1.13.0` by default) against the endpoint in `SYSTEMONE_ENDPOINT`, which defaults to TypeSafe at `https://api.typesafe.ai/v1/systemone`. Review your provider's current legal terms — for TypeSafe, [legal terms](https://docs.typesafe.ai/legal), including privacy and retention; a no-training commitment does not mean zero retention.
|
|
596
603
|
|
|
597
604
|
```text
|
|
598
605
|
Normal search
|
|
@@ -611,14 +618,35 @@ mcp({ search: "calendar", searchMode: "semantic" })
|
|
|
611
618
|
The quickest desktop setup is:
|
|
612
619
|
|
|
613
620
|
```sh
|
|
614
|
-
pi-mcp-adapter key set
|
|
621
|
+
pi-mcp-adapter key set systemone
|
|
615
622
|
```
|
|
616
623
|
|
|
617
|
-
That is enough to use semantic search across all enabled MCP tools. Run `/mcp jev setup` in Pi when you want to restrict which enabled servers may share semantic-search data. The command saves a project-scoped allowlist and reloads Pi automatically. Verify the stored credential at any time with `pi-mcp-adapter key status
|
|
624
|
+
That is enough to use semantic search across all enabled MCP tools. Run `/mcp jev setup` in Pi when you want to restrict which enabled servers may share semantic-search data. The command saves a project-scoped allowlist and reloads Pi automatically. Verify the stored credential at any time with `pi-mcp-adapter key status systemone`.
|
|
625
|
+
|
|
626
|
+
`SYSTEMONE_API_KEY` is for CI/headless use and overrides the keyring. Stdio MCP subprocesses inherit the host environment by default, so set `inheritEnv: false` where they must not receive it. The script worker receives no key, SDK, endpoint, headers, or environment.
|
|
627
|
+
|
|
628
|
+
##### Choosing a provider endpoint
|
|
618
629
|
|
|
619
|
-
|
|
630
|
+
System One decisions are the same API at different origins, so pointing at another provider needs an endpoint and, usually, a model:
|
|
620
631
|
|
|
621
|
-
|
|
632
|
+
| Provider | `SYSTEMONE_ENDPOINT` | Model |
|
|
633
|
+
| --- | --- | --- |
|
|
634
|
+
| TypeSafe (default) | `https://api.typesafe.ai/v1/systemone` | `jev-1.13.0` |
|
|
635
|
+
| OpenCode Zen | `https://opencode.ai/zen/v1/systemone` | `jev-1.13` |
|
|
636
|
+
| Command Code | `https://api.commandcode.ai/provider/v1/systemone` | `typesafe/jev` |
|
|
637
|
+
| OpenRouter | `https://openrouter.ai/api/alpha/decisions` | `typesafe/jev-1.13` |
|
|
638
|
+
|
|
639
|
+
These are example configurations, subject to each provider's current documentation ([OpenCode Zen](https://opencode.ai/docs/zen/), [Command Code](https://commandcode.ai/docs/provider), [TypeSafe](https://docs.typesafe.ai/)).
|
|
640
|
+
|
|
641
|
+
The endpoint must be an absolute `https` URL with a path. A set-but-invalid `SYSTEMONE_ENDPOINT` disables Jev instead of falling back to the default. Treat the endpoint as trusted configuration: it receives the API key and the judgment payload. Credentials are stored per endpoint, so switching endpoints does not overwrite a saved key. Set the model with:
|
|
642
|
+
|
|
643
|
+
```json
|
|
644
|
+
{ "settings": { "jev": { "model": "jev-1.13" } } }
|
|
645
|
+
```
|
|
646
|
+
|
|
647
|
+
The older `TYPESAFE_API_KEY` variable still works for the default TypeSafe endpoint and is never sent to any other endpoint.
|
|
648
|
+
|
|
649
|
+
Semantic search sends the query text, server names, normalized and original tool names, tool paths, and descriptions to the configured endpoint. It does not send tool results. `allowedServers` restricts semantic search to named servers. `scriptEvaluation` is a separate opt-in that may send the state and MCP-derived results declared in each evaluation; when enabled, it requires an explicit source allowlist.
|
|
622
650
|
|
|
623
651
|
```json
|
|
624
652
|
{
|
|
@@ -634,7 +662,7 @@ Semantic search sends the query text, server names, normalized and original tool
|
|
|
634
662
|
|
|
635
663
|
Request semantic discovery explicitly with `mcp({ search: "triage customer reports", searchMode: "semantic" })` or `tools.search({ query: "triage customer reports", searchMode: "semantic" })`. Regex is incompatible. Timeout, rate-limit, and service failures return marked lexical fallback; credential, policy, configuration, and response failures do not. If no allowed server has cached tools, search explains how to connect a server or update the allowlist; if Jev decides no tool fits, the result says that Jev abstained.
|
|
636
664
|
|
|
637
|
-
Optional `jev` controls bound timeout/retries, request and script budgets, semantic candidates (at most 127), and minimum probability. The cumulative token budget uses provider-reported input plus output usage. Exact pre-response admission is unavailable without the provider tokenizer, so byte/question/state limits bound requests before dispatch; a response that exceeds the remaining token budget is discarded and exhausts it. The endpoint
|
|
665
|
+
Optional `jev` controls bound timeout/retries, request and script budgets, semantic candidates (at most 127), and minimum probability. The cumulative token budget uses provider-reported input plus output usage. Exact pre-response admission is unavailable without the provider tokenizer, so byte/question/state limits bound requests before dispatch; a response that exceeds the remaining token budget is discarded and exhausts it. The endpoint is set by `SYSTEMONE_ENDPOINT`; headers and SDK logging are not configurable.
|
|
638
666
|
|
|
639
667
|
`await jev.evaluate({ state, questions, sources })` returns `{ ok, data }` or `{ ok: false, error }`. `sources` must name every MCP server represented in `state`. The host also conservatively taints the whole script with every server-attributed MCP call result or error: declared and observed sources must all be enabled and in `allowedServers`, so copying data or omitting/mislabeling `sources` cannot bypass policy. The taint remains for later direct evaluations and semantic searches even when the script did not retain the call result. Direct and semantic provider attempts share the per-script count, UTF-8 request-byte, token, and deadline budgets; later `tools.call` operations still require normal authentication and approval. See `examples/jev-semantic-filter.mjs` and `examples/jev-accessibility-loop.mjs`.
|
|
640
668
|
|
|
@@ -792,6 +820,8 @@ Each direct tool costs ~150-300 tokens in the system prompt (name + description
|
|
|
792
820
|
|
|
793
821
|
Direct tools register from the metadata cache in the Pi agent dir (`~/.pi/agent/mcp-cache.json` by default, or `$PI_CODING_AGENT_DIR/mcp-cache.json` when set), so no server connections are needed at startup. On the first session after adding `directTools` to a new server, the cache won't exist yet — tools fall back to proxy-only while the cache populates, then the extension hot-loads the refreshed direct tools into the current session. When `mcp({ connect: "<server>" })` is what discovers them, the connect result lists the new tools in `addedToolNames`, so Pi can load their definitions from that point in the transcript instead of rewriting the active tool list. Servers that advertise MCP list-change notifications refresh the current session when their tool or resource list changes. On Pi versions that expose `pi.unregisterTool()`, stale direct tools are removed from the registry during refresh; older Pi versions still deactivate them from the active tool set. To force a refresh: `/mcp reconnect <server>`.
|
|
794
822
|
|
|
823
|
+
For faster startup, set `settings.deferWithMissingMetadata` to `true`. Servers with missing or invalid metadata (expired, mismatched, or non-cacheable) then contribute no tools, prompts, resources, or search entries until the first MCP operation starts the runtime and loads live metadata; the `mcp` gateway stays available. Because Pi cannot unregister slash commands, cached prompt commands also wait for live metadata under this setting. `eager`/`keep-alive` servers and cold `MCP_DIRECT_TOOLS` selections still start immediately.
|
|
824
|
+
|
|
795
825
|
Models sometimes encode an object or array argument as a JSON string. Set `settings.strictDirectToolArguments` to `true` to recover one such layer for schema-declared object and array properties, then validate the complete input against the advertised schema before execution.
|
|
796
826
|
|
|
797
827
|
Set `settings.directToolResultDetails` to `"bounded"` when an extension needs structured MCP result fields in Pi's direct-tool result details. The same output guard limits apply. Small leading structured fields stay available, while large fields receive bounded summaries and the complete guarded result follows the output guard's spill-file policy. The default `"lean"` mode keeps the existing server and tool metadata only.
|