@phyzess/pappra 0.1.0-beta.8 → 0.1.0-beta.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/README.md +4 -2
- package/dist/app/collaboration.js +6 -13
- package/dist/hosts/pi/rpc.d.ts +2 -0
- package/dist/hosts/pi/rpc.js +39 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -55,7 +55,9 @@ configured knowledge sources.
|
|
|
55
55
|
|
|
56
56
|
Optional examples have prerequisites rather than generated files: code-graph and
|
|
57
57
|
host commands require the selected external CLI/support, and collaboration
|
|
58
|
-
requires an explicit controller.
|
|
58
|
+
requires an explicit controller. `--controller pi-rpc` is the host-directs/Pi-executes
|
|
59
|
+
path, verified end to end against Pi 1.3.0; see [Pi RPC collaboration](docs/pi-rpc.md).
|
|
60
|
+
They are not needed for the core workflow above.
|
|
59
61
|
|
|
60
62
|
## What it manages
|
|
61
63
|
|
|
@@ -87,7 +89,7 @@ The check runs the source policy, type checks, formatting, deterministic tests a
|
|
|
87
89
|
|
|
88
90
|
## Status and limits
|
|
89
91
|
|
|
90
|
-
Pappra is development software (`0.1.0-beta.
|
|
92
|
+
Pappra is development software (`0.1.0-beta.9`) published as `@phyzess/pappra` under the `beta` dist-tag. Releases are published from GitHub Actions with npm trusted publishing (OIDC), so no npm token is stored in this repository. Pin either the moving `beta` tag or an exact version such as `@phyzess/pappra@0.1.0-beta.9`, because pre-release versions are never republished.
|
|
91
93
|
|
|
92
94
|
The deterministic suite covers synthetic workspaces, fixtures and local process boundaries. It does not establish real-model behavior, native host callability on every platform, CodeGraph completeness, Windows/Linux parity or production performance. A host adapter version pin is an observed support claim, not proof that a particular native installation will load or run correctly.
|
|
93
95
|
|
|
@@ -461,17 +461,6 @@ function currentNativeResult(file, baseline) {
|
|
|
461
461
|
return null;
|
|
462
462
|
}
|
|
463
463
|
}
|
|
464
|
-
function regularFileSize(file) {
|
|
465
|
-
if (file === null || !path.isAbsolute(file))
|
|
466
|
-
return null;
|
|
467
|
-
try {
|
|
468
|
-
const observed = fs.lstatSync(file);
|
|
469
|
-
return observed.isFile() ? observed.size : null;
|
|
470
|
-
}
|
|
471
|
-
catch {
|
|
472
|
-
return null;
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
464
|
function writeNewFile(file, bytes) {
|
|
476
465
|
fs.mkdirSync(path.dirname(file), { recursive: true, mode: 0o700 });
|
|
477
466
|
fs.writeFileSync(file, bytes, { flag: 'wx', mode: 0o600 });
|
|
@@ -1359,10 +1348,14 @@ export class PiRpcController {
|
|
|
1359
1348
|
possible_start: stage === 'identity',
|
|
1360
1349
|
};
|
|
1361
1350
|
}
|
|
1362
|
-
|
|
1363
|
-
|
|
1351
|
+
let nativeSessionFile = null;
|
|
1352
|
+
let nativeSessionBaseline = 0;
|
|
1364
1353
|
try {
|
|
1365
1354
|
await started.session.prompt();
|
|
1355
|
+
// The handle sampled the baseline before it sent the prompt; read it afterwards so
|
|
1356
|
+
// both values describe the launch that just completed.
|
|
1357
|
+
nativeSessionFile = started.session.sessionFile();
|
|
1358
|
+
nativeSessionBaseline = started.session.promptBaseline();
|
|
1366
1359
|
}
|
|
1367
1360
|
catch (error) {
|
|
1368
1361
|
await started.session.finish().catch(() => undefined);
|
package/dist/hosts/pi/rpc.d.ts
CHANGED
|
@@ -461,6 +461,8 @@ export declare function startOwnedPiRpc(options: PiOptions): Promise<{
|
|
|
461
461
|
pid: number | null;
|
|
462
462
|
expectedSessionId: string | null;
|
|
463
463
|
sessionFile: () => string | null;
|
|
464
|
+
/** Byte offset sampled immediately before the prompt was sent. */
|
|
465
|
+
promptBaseline: () => number;
|
|
464
466
|
/** Read-only native query. Repeatable; always recorded through the protocol. */
|
|
465
467
|
query(): Promise<{
|
|
466
468
|
at: string;
|
package/dist/hosts/pi/rpc.js
CHANGED
|
@@ -680,6 +680,7 @@ export async function startOwnedPiRpc(options) {
|
|
|
680
680
|
let reportedSessionFile = null;
|
|
681
681
|
let boundSessionFile = null;
|
|
682
682
|
let promptSent = false;
|
|
683
|
+
let promptBaseline = 0;
|
|
683
684
|
let lastPromptOrdinal = 0;
|
|
684
685
|
let operationError = null;
|
|
685
686
|
let finishPromise = null;
|
|
@@ -822,6 +823,8 @@ export async function startOwnedPiRpc(options) {
|
|
|
822
823
|
pid: child.pid ?? null,
|
|
823
824
|
expectedSessionId: admission.expected_identity,
|
|
824
825
|
sessionFile: () => boundSessionFile,
|
|
826
|
+
/** Byte offset sampled immediately before the prompt was sent. */
|
|
827
|
+
promptBaseline: () => promptBaseline,
|
|
825
828
|
/** Read-only native query. Repeatable; always recorded through the protocol. */
|
|
826
829
|
async query() {
|
|
827
830
|
try {
|
|
@@ -894,7 +897,24 @@ export async function startOwnedPiRpc(options) {
|
|
|
894
897
|
throw new PiRpcRefusal('prompt_already_sent', 'invalid', 'one frozen prompt per launch');
|
|
895
898
|
assertNamespaceGuard(opts);
|
|
896
899
|
assertCurrentAuthority({ requireResources: true });
|
|
897
|
-
|
|
900
|
+
// Pi creates the session file lazily, on the first persisted message. The
|
|
901
|
+
// pre-prompt check therefore verifies the reported session id without requiring
|
|
902
|
+
// the header; the post-prompt check requires the bound header before the run is
|
|
903
|
+
// accepted.
|
|
904
|
+
await assertIdentity({ requireBinding: false });
|
|
905
|
+
// The controller publishes only records written after this baseline, so it must
|
|
906
|
+
// be sampled before the prompt creates the first message.
|
|
907
|
+
const baselineFile = reportedSessionFile;
|
|
908
|
+
promptBaseline = (() => {
|
|
909
|
+
if (baselineFile === null)
|
|
910
|
+
return 0;
|
|
911
|
+
try {
|
|
912
|
+
return fs.statSync(baselineFile).size;
|
|
913
|
+
}
|
|
914
|
+
catch {
|
|
915
|
+
return 0;
|
|
916
|
+
}
|
|
917
|
+
})();
|
|
898
918
|
const ordinalBefore = rpc.recordCount();
|
|
899
919
|
const response = await request('prompt', { message: opts.promptText });
|
|
900
920
|
const disposition = response.data?.disposition;
|
|
@@ -902,6 +922,24 @@ export async function startOwnedPiRpc(options) {
|
|
|
902
922
|
!['started', 'queued', 'handled'].includes(disposition)) {
|
|
903
923
|
throw new PiRpcRefusal('prompt_not_accepted', 'needs_input', `disposition ${disposition}`);
|
|
904
924
|
}
|
|
925
|
+
// The header row is flushed just after the prompt is accepted, so bind with a
|
|
926
|
+
// short bounded retry instead of racing the writer.
|
|
927
|
+
const bindDeadline = Date.now() + 2_000;
|
|
928
|
+
for (;;) {
|
|
929
|
+
try {
|
|
930
|
+
await assertIdentity({ requireBinding: true });
|
|
931
|
+
break;
|
|
932
|
+
}
|
|
933
|
+
catch (error) {
|
|
934
|
+
const retryable = error instanceof PiRpcRefusal &&
|
|
935
|
+
(error.code === 'native_session_file_unavailable' ||
|
|
936
|
+
error.code === 'native_session_header_invalid') &&
|
|
937
|
+
Date.now() < bindDeadline;
|
|
938
|
+
if (!retryable)
|
|
939
|
+
throw error;
|
|
940
|
+
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
941
|
+
}
|
|
942
|
+
}
|
|
905
943
|
promptSent = true;
|
|
906
944
|
lastPromptOrdinal = ordinalBefore;
|
|
907
945
|
proof.prompt = {
|