@matuto-ai/pi-broker-connector 0.3.0 → 0.3.1

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
@@ -2,7 +2,7 @@
2
2
 
3
3
  A native Pi extension providing durable, session-bound messaging through the [Psst broker](https://github.com/matuto-ai/psst). Runs **inside the Pi process in your existing sandbox**. No host launcher, local model, provider subscription, or additional service is required by the connector.
4
4
 
5
- **Version 0.3.0:** native private setup, persistent installation selection and automatic reconnection of independent Pi sessions, retaining automatic native delivery and transport-auth pause protection. Tested with the official Pi 1.4.0 SDK and a local fixture model; live authenticated user-sandbox acceptance remains a separate step.
5
+ **Version 0.3.1:** native private setup, persistent installation selection and automatic reconnection of independent Pi sessions, retaining automatic native delivery and transport-auth pause protection. Tested with the official Pi 1.4.0 SDK and a local fixture model; live authenticated user-sandbox acceptance remains a separate step.
6
6
 
7
7
  ## Requirements
8
8
 
@@ -33,7 +33,7 @@ This uses the default branch. To pin a reviewed commit, append `@` and its exact
33
33
  ### From npm (only after publication)
34
34
 
35
35
  ```sh
36
- pi install npm:@matuto-ai/pi-broker-connector@0.3.0
36
+ pi install npm:@matuto-ai/pi-broker-connector@0.3.1
37
37
  ```
38
38
 
39
39
  The command requires the version to be present on npm. If publication is still pending, use a reviewed checkout instead.
@@ -79,7 +79,7 @@ Use the existing bundle path; keep its `token` next to `connection.json`. After
79
79
  Install or update **inside the same sandbox**, then use `/reload` in the running Pi:
80
80
 
81
81
  ```sh
82
- pi install npm:@matuto-ai/pi-broker-connector@0.3.0
82
+ pi install npm:@matuto-ai/pi-broker-connector@0.3.1
83
83
  ```
84
84
 
85
85
  This installer command is not a second agent session. No sandbox recreation or Pi process restart is required. Version 0.1.1 does not have `/psst-connect`; 0.1.2 adds that command, while automatic delivery requires 0.2.0 or later.
@@ -177,7 +177,7 @@ Tests cover private bundle validation, exact session isolation, duplicate owners
177
177
 
178
178
  ## Publishing
179
179
 
180
- This release uses package version `0.3.0` and matching GitHub release tag `v0.3.0`. The release workflow publishes the package only after its checks pass.
180
+ This release uses package version `0.3.1` and matching GitHub release tag `v0.3.1`. The release workflow publishes the package only after its checks pass.
181
181
 
182
182
  The release workflow follows the existing Pi plugin convention: a published GitHub release triggers checks and npm publishing. It requires a `v<package.version>` tag and runs the native host gate before publishing. Nothing is published by CI on pull requests or ordinary pushes.
183
183
 
@@ -240,3 +240,7 @@ component, connects to a real fixture HTTPS broker, and recreates HOME while
240
240
  preserving the agent directory. It asserts one credential and two distinct
241
241
  sessions without a second setup. No model turn or authenticated user-sandbox
242
242
  acceptance is claimed. The broker checkout must include its enrollment TLS fixture.
243
+
244
+ ### Masked-field keyboard regression tests
245
+
246
+ `npm test` requires Python 3 on Linux for the real POSIX PTY keyboard tests. They use only synthetic input and the pinned official Pi TUI 1.4.0 development dependency. Runtime imports resolve through Pi’s native extension loader; no terminal keyboard mode is changed by the connector itself. Legacy text/paste and Kitty printable input are supported, while control keys use the public host decoder. This does not claim complete xterm `modifyOtherKeys` printable-key support.
package/package.json CHANGED
@@ -1,15 +1,50 @@
1
1
  {
2
2
  "name": "@matuto-ai/pi-broker-connector",
3
- "version": "0.3.0",
3
+ "version": "0.3.1",
4
4
  "description": "Session-bound Psst broker messaging tools for Pi",
5
5
  "type": "module",
6
6
  "license": "MIT",
7
- "repository": { "type": "git", "url": "git+https://github.com/matuto-ai/pi-broker-connector.git" },
8
- "engines": { "node": ">=24.19.0 <25" },
9
- "keywords": ["pi-package", "pi", "psst", "broker"],
10
- "files": ["extensions/", "src/", "vendor/", "README.md", "LICENSE"],
11
- "pi": { "extensions": ["./extensions/psst.ts"] },
12
- "peerDependencies": { "@earendil-works/pi-coding-agent": "*", "typebox": "*" },
13
- "scripts": { "test": "node --test test/*.test.mjs", "check": "node scripts/check.mjs", "test:host": "node --test test/native-host.probe.mjs", "prepack": "npm run check && npm test" },
14
- "publishConfig": { "access": "public", "registry": "https://registry.npmjs.org/" }
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/matuto-ai/pi-broker-connector.git"
10
+ },
11
+ "engines": {
12
+ "node": ">=24.19.0 <25"
13
+ },
14
+ "keywords": [
15
+ "pi-package",
16
+ "pi",
17
+ "psst",
18
+ "broker"
19
+ ],
20
+ "files": [
21
+ "extensions/",
22
+ "src/",
23
+ "vendor/",
24
+ "README.md",
25
+ "LICENSE"
26
+ ],
27
+ "pi": {
28
+ "extensions": [
29
+ "./extensions/psst.ts"
30
+ ]
31
+ },
32
+ "peerDependencies": {
33
+ "@earendil-works/pi-coding-agent": "*",
34
+ "typebox": "*",
35
+ "@earendil-works/pi-tui": "^1.4.0"
36
+ },
37
+ "scripts": {
38
+ "test": "node --test test/*.test.mjs",
39
+ "check": "node scripts/check.mjs",
40
+ "test:host": "node --test test/native-host.probe.mjs",
41
+ "prepack": "npm run check && npm test"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public",
45
+ "registry": "https://registry.npmjs.org/"
46
+ },
47
+ "devDependencies": {
48
+ "@earendil-works/pi-tui": "1.4.0"
49
+ }
15
50
  }
@@ -1,25 +1,34 @@
1
+ import { matchesKey, isKeyRelease, decodeKittyPrintable } from '@earendil-works/pi-tui';
1
2
  import { LocalError } from '../vendor/broker/reference/errors.mjs';
2
3
 
3
4
  // A focused native component: the value never enters Pi's editor or a message.
4
- // Only base64url ticket bytes are accepted, rendering is always masked.
5
+ // Use public host decoders for control keys and Kitty printable input; legacy text/paste stays masked.
5
6
  export function maskedPairingComponent({done,requestRender}) {
6
- let value='',closed=false,pasting=false;
7
- const finish=result=>{if(closed)return;closed=true;value='';done(result);};
7
+ let value='',closed=false,pasting=false,paste='',invalidPaste=false,hint=false;
8
+ const finish=result=>{if(closed)return;closed=true;value='';paste='';done(result);};
9
+ const append=data=>{if(/^[A-Za-z0-9_-]+$/.test(data)&&value.length+data.length<=43){value+=data;hint=false;}};
8
10
  return {
9
- render(width){return ['Psst: enter the one-time pairing secret (hidden)', '*'.repeat(value.length), 'Enter: connect Esc: cancel'].map(line=>line.slice(0,Math.max(0,width)));},
11
+ render(width){return ['Psst: enter the one-time pairing secret (hidden)', '*'.repeat(value.length), hint?'Paste the complete 43-character pairing secret.':'Enter: connect Esc or Ctrl+C: cancel'].map(line=>line.slice(0,Math.max(0,width)));},
10
12
  invalidate(){},
11
13
  handleInput(data){
12
- if(closed)return;
13
- if(data==='\x1b'||data==='\x03'){finish(undefined);return;}
14
- if(data==='\r'||data==='\n'){if(!pasting&&/^[A-Za-z0-9_-]{43}$/.test(value))finish(value);return;}
15
- if(data==='\x7f'||data==='\b'){value=value.slice(0,-1);requestRender();return;}
16
- // Pi TUI may deliver bracketed paste as one event or separate chunks.
17
- if(data.startsWith('\x1b[200~')){pasting=true;data=data.slice(6);}
18
- if(data.endsWith('\x1b[201~')){pasting=false;data=data.slice(0,-6);}
19
- if(/^[A-Za-z0-9_-]+$/.test(data)&&value.length+data.length<=43)value+=data;
14
+ if(closed||typeof data!=='string'||isKeyRelease(data))return;
15
+ if(matchesKey(data,'escape')||matchesKey(data,'ctrl+c')){finish(undefined);return;}
16
+ if(matchesKey(data,'enter')){if(!pasting){if(/^[A-Za-z0-9_-]{43}$/.test(value))finish(value);else{hint=true;requestRender();}}return;}
17
+ if(!pasting&&matchesKey(data,'backspace')){value=value.slice(0,-1);hint=false;requestRender();return;}
18
+ // Pi normally wraps a whole paste; tolerate marker/body/end delivered separately.
19
+ if(data.startsWith('\x1b[200~')){pasting=true;paste='';invalidPaste=false;data=data.slice(6);}
20
+ if(pasting){
21
+ const end=data.indexOf('\x1b[201~');
22
+ const body=end<0?data:data.slice(0,end);
23
+ if(!/^[A-Za-z0-9_-]*$/.test(body)||paste.length+body.length>43)invalidPaste=true;
24
+ if(!invalidPaste)paste+=body;
25
+ if(end>=0){if(data.slice(end+6))invalidPaste=true;if(!invalidPaste)append(paste);else hint=true;paste='';pasting=false;invalidPaste=false;}
26
+ }else{
27
+ append(decodeKittyPrintable(data)??data);
28
+ }
20
29
  requestRender();
21
30
  },
22
- dispose(){closed=true;value='';},
31
+ dispose(){closed=true;value='';paste='';},
23
32
  };
24
33
  }
25
34
  export async function promptPairingSecret(ctx) {