jorgex-pi 0.8.31 → 0.8.32
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 +5 -2
- package/contract/jorgex-pi.v1.json +2 -2
- package/extensions/mcp-engram.ts +29 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -132,7 +132,10 @@ Context7 uses the canonical endpoint `https://mcp.context7.com/mcp`. `CONTEXT7_A
|
|
|
132
132
|
|
|
133
133
|
The runner's `status` and `doctor` commands report whether Context7 configuration permits registration; `available` does not mean that an HTTP handshake has occurred. `sync` fails closed on a Context7 conflict and does not modify MCP configuration. At `session_start`, JorgeX registers Context7 and strict DevTools through the external adapter's runtime event bus; it does not create a bundled adapter or fallback factory. Missing, duplicate, malformed, unreadable, or conflicting official setup fails closed with a remediation to run `engram setup pi` and correct the external configuration.
|
|
134
134
|
|
|
135
|
-
When a compatible Stack projection provides `PI_CODING_AGENT_DIR/jorgex-pi/devtools.v1.json`, the bridge validates
|
|
135
|
+
When a compatible Stack projection provides `PI_CODING_AGENT_DIR/jorgex-pi/devtools.v1.json`, the bridge validates the optional handoff and registers strict DevTools through the external adapter. The historical `schemaVersion: 1` form remains accepted for existing receipts: it requires an absolute executable command and `dlx chrome-devtools-mcp@<exact-stable-version> --isolated --redact-network-headers --no-performance-crux --no-usage-statistics`. The new `schemaVersion: 2` form uses an absolute executable Node command and `args: ["/absolute/path/to/managed-devtools.mjs", "--isolated", "--redact-network-headers", "--no-performance-crux", "--no-usage-statistics"]`; the entry must exist as a regular local JS file, and `dlx` is rejected. Both forms have exactly the four fields `schemaVersion`, `enabled: true`, `command`, and `args`; extra fields and changed flags fail closed. Pi reads but never edits the handoff or fetches browser packages. Stack owns its lifecycle, verifies the installed tree and launcher integrity before execution, and must publish the local form only after verifying the package; **Pi validates shape and executability, not the checksum or ownership of the launcher**. DevTools is advertised only after the handoff and external adapter registration succeed. The registration stays lazy/proxy (`directTools: false`), and a change to the handoff requires reloading Pi.
|
|
136
|
+
|
|
137
|
+
This capability is consumer-only: the currently published Stack release does not produce the v2 handoff. The separate Stack browser PR must implement and verify the byte-bound launcher before enabling new local DevTools installations; publishing Pi alone does not change personal configurations or make v1 `dlx` byte-bound.
|
|
138
|
+
For v2, the executable must resolve to the same Node binary running Pi. If Pi later uses a different Node installation, Stack must re-verify and re-project the local handoff; Pi rejects the old command rather than launching it with an unknown interpreter.
|
|
136
139
|
|
|
137
140
|
The official setup owns the Engram binary, database, and memories. Pi only validates the external configuration needed for the session and never installs, updates, removes, or takes ownership of that state. Child environment handling is provider/runtime-owned; JorgeX defines no environment allowlist. Provider-managed `gentle-engram` hooks may automatically persist session, prompt, and compaction context; JorgeX does not own or configure those hooks.
|
|
138
141
|
|
|
@@ -181,7 +184,7 @@ The optional Stack handoff is `PI_CODING_AGENT_DIR/jorgex-pi/playwright.v1.json`
|
|
|
181
184
|
}
|
|
182
185
|
```
|
|
183
186
|
|
|
184
|
-
Pi accepts the handoff only when `schemaVersion` is `1`, `enabled` is `true`, `version` is an exact stable semver, `command` is absolute and executable, and invoking that path with `--version` returns exactly the handoff version. The resolver does not search `PATH`, inspect browser profiles, open a user session, or test whether a live browser can launch. Stack owns
|
|
187
|
+
Pi accepts the handoff only when `schemaVersion` is `1`, `enabled` is `true`, `version` is an exact stable semver, `command` is absolute and executable, and invoking that path with `--version` returns exactly the handoff version. The resolver does not search `PATH`, inspect browser profiles, open a user session, or test whether a live browser can launch. Stack owns acquisition of the shared CLI and Chromium, including browser readiness checks; the Pi capability check validates only the executable handoff and does not download, checksum, or authenticate the CLI binary.
|
|
185
188
|
|
|
186
189
|
When the handoff is absent, malformed, or fails the version check, the capability stays hidden and the browser guidance is omitted. A manually written file that satisfies the same schema and executable/version checks is accepted; Pi does not authenticate its provenance. Once a valid handoff is present, Pi exposes the routing with the managed command path. The bootstrap resolves it in `before_agent_start` for each agent turn and does not rewrite it; changing or removing the file is re-evaluated on the next turn. The capability is advertised as `playwright-handoff-v1`; this resolver state does not certify live browser readiness. Its adoption is a separate Stack change and does not alter Pi's canonical snapshot or shared source commit.
|
|
187
190
|
|
package/extensions/mcp-engram.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { accessSync, constants, readFileSync, statSync } from "node:fs";
|
|
1
|
+
import { accessSync, constants, lstatSync, readFileSync, realpathSync, statSync } from "node:fs";
|
|
2
2
|
import { posix, win32 } from "node:path";
|
|
3
3
|
import { fileURLToPath } from "node:url";
|
|
4
4
|
import { inspectContext7Config, inspectOfficialPackages, resolvePiAgentDir } from "./context7-config.mjs";
|
|
@@ -25,6 +25,7 @@ const DEVTOOLS_FIXED_SUFFIX_ARGS = [
|
|
|
25
25
|
"--no-performance-crux",
|
|
26
26
|
"--no-usage-statistics",
|
|
27
27
|
];
|
|
28
|
+
const CONTROL_CHARACTERS = /[\u0000-\u001f\u007f]/;
|
|
28
29
|
|
|
29
30
|
// The bridge never invokes setup or writes settings/MCP state. It inspects the
|
|
30
31
|
// official external setup and reports the state; the bootstrap registers only
|
|
@@ -198,16 +199,19 @@ function readChromeDevToolsHandoff({ env, platform }) {
|
|
|
198
199
|
if (keys.join("\0") !== ["args", "command", "enabled", "schemaVersion"].join("\0")) {
|
|
199
200
|
throw new Error(`Chrome DevTools handoff has an invalid schema at ${handoffPath}`);
|
|
200
201
|
}
|
|
201
|
-
if (handoff.schemaVersion !== 1 || handoff.enabled !== true) {
|
|
202
|
+
if ((handoff.schemaVersion !== 1 && handoff.schemaVersion !== 2) || handoff.enabled !== true) {
|
|
202
203
|
throw new Error(`Chrome DevTools handoff has an unsupported schema at ${handoffPath}`);
|
|
203
204
|
}
|
|
204
|
-
if (typeof handoff.command !== "string" || !paths.isAbsolute(handoff.command)) {
|
|
205
|
+
if (typeof handoff.command !== "string" || CONTROL_CHARACTERS.test(handoff.command) || !paths.isAbsolute(handoff.command)) {
|
|
205
206
|
throw new Error(`Chrome DevTools handoff command must be an absolute path at ${handoffPath}`);
|
|
206
207
|
}
|
|
207
208
|
if (!isExecutable(handoff.command, platform)) {
|
|
208
209
|
throw new Error(`Chrome DevTools handoff command is not executable at ${handoffPath}`);
|
|
209
210
|
}
|
|
210
|
-
if (!
|
|
211
|
+
if (handoff.schemaVersion === 2 && !isCurrentNode(handoff.command, paths, platform)) {
|
|
212
|
+
throw new Error(`Chrome DevTools handoff command must be this Pi runtime's Node executable at ${handoffPath}`);
|
|
213
|
+
}
|
|
214
|
+
if (handoff.schemaVersion === 1 ? !isDevToolsArgs(handoff.args) : !isLocalDevToolsArgs(handoff.args, paths)) {
|
|
211
215
|
throw new Error(`Chrome DevTools handoff has invalid arguments at ${handoffPath}`);
|
|
212
216
|
}
|
|
213
217
|
return { command: handoff.command, args: handoff.args };
|
|
@@ -219,6 +223,27 @@ function isDevToolsArgs(args) {
|
|
|
219
223
|
return args.slice(2).every((arg, index) => arg === DEVTOOLS_FIXED_SUFFIX_ARGS[index]);
|
|
220
224
|
}
|
|
221
225
|
|
|
226
|
+
function isLocalDevToolsArgs(args, paths) {
|
|
227
|
+
if (!Array.isArray(args) || args.length !== DEVTOOLS_FIXED_SUFFIX_ARGS.length + 1) return false;
|
|
228
|
+
const entry = args[0];
|
|
229
|
+
if (typeof entry !== "string" || CONTROL_CHARACTERS.test(entry) || !paths.isAbsolute(entry)
|
|
230
|
+
|| ![".js", ".mjs"].includes(paths.extname(entry).toLowerCase())) return false;
|
|
231
|
+
try {
|
|
232
|
+
if (!lstatSync(entry).isFile()) return false;
|
|
233
|
+
} catch {
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
return args.slice(1).every((arg, index) => arg === DEVTOOLS_FIXED_SUFFIX_ARGS[index]);
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
function isCurrentNode(command, paths, platform) {
|
|
240
|
+
try {
|
|
241
|
+
return samePath(realpathSync(command), realpathSync(process.execPath), paths, platform);
|
|
242
|
+
} catch {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
222
247
|
function isDevToolsPackageArg(arg) {
|
|
223
248
|
if (typeof arg !== "string" || !arg.startsWith(DEVTOOLS_PACKAGE_PREFIX)) return false;
|
|
224
249
|
return isStableExactVersion(arg.slice(DEVTOOLS_PACKAGE_PREFIX.length));
|