@mjasnikovs/pi-task 0.40.35 → 0.40.37
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.
|
@@ -9,6 +9,8 @@ export declare const CHILD_BASE_ARGS: readonly ["--print", "--no-skills", "--no-
|
|
|
9
9
|
export interface WritableLike {
|
|
10
10
|
write(chunk: string): boolean;
|
|
11
11
|
end(): void;
|
|
12
|
+
/** Optional so a mock stdin stays two methods; a real pipe always has it. */
|
|
13
|
+
on?(event: 'error', listener: (err: unknown) => void): unknown;
|
|
12
14
|
}
|
|
13
15
|
export interface ProcLike extends EventEmitter {
|
|
14
16
|
/** Present only when the child was spawned with stdin 'pipe' (prompt delivery). */
|
|
@@ -236,6 +236,10 @@ export function runChild(spawn, invocation, cwd, signal, opts) {
|
|
|
236
236
|
...(invocation.env ? { env: invocation.env } : {})
|
|
237
237
|
});
|
|
238
238
|
if (usesStdin) {
|
|
239
|
+
// A child killed before it read the prompt leaves the pipe broken, and an
|
|
240
|
+
// unhandled EPIPE on stdin takes the whole process down. The child's own
|
|
241
|
+
// exit is what reports that run; this write has nothing left to say.
|
|
242
|
+
proc.stdin?.on?.('error', () => { });
|
|
239
243
|
// pi reads the prompt from stdin and waits for EOF, so write then end.
|
|
240
244
|
proc.stdin?.write(invocation.stdin);
|
|
241
245
|
proc.stdin?.end();
|
|
@@ -113,9 +113,9 @@ export interface DeepSessionFacts {
|
|
|
113
113
|
* The three request-shaped facts, computed from the log and from nothing else. The
|
|
114
114
|
* driver records `sessionRequests` and calls this; the values are exactly what the
|
|
115
115
|
* pre-log driver computed by filtering the same map (the sign-in request is the
|
|
116
|
-
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
117
|
-
* same-origin
|
|
118
|
-
*
|
|
116
|
+
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
117
|
+
* the same-origin XHR/fetch issued at or after the sign-in request, that request
|
|
118
|
+
* itself excluded).
|
|
119
119
|
*/
|
|
120
120
|
export declare function deriveLegacyFacts(log: SessionRequest[]): Pick<DeepSessionFacts, 'authRequest' | 'postAuthDataAttempted' | 'postAuthData2xx'>;
|
|
121
121
|
/**
|
|
@@ -202,9 +202,9 @@ export function pinnedLocalPort(vars) {
|
|
|
202
202
|
* The three request-shaped facts, computed from the log and from nothing else. The
|
|
203
203
|
* driver records `sessionRequests` and calls this; the values are exactly what the
|
|
204
204
|
* pre-log driver computed by filtering the same map (the sign-in request is the
|
|
205
|
-
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
206
|
-
* same-origin
|
|
207
|
-
*
|
|
205
|
+
* first same-origin non-GET issued at or after the submit; the data requests are
|
|
206
|
+
* the same-origin XHR/fetch issued at or after the sign-in request, that request
|
|
207
|
+
* itself excluded).
|
|
208
208
|
*/
|
|
209
209
|
export function deriveLegacyFacts(log) {
|
|
210
210
|
const auth = log.find(r => r.phase === 'auth') ?? null;
|
|
@@ -659,10 +659,15 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
659
659
|
// judges it is the chain's last, so the first hop stays and the eventual
|
|
660
660
|
// response lands on it. Overwriting reads a POST that 302s as a GET, and
|
|
661
661
|
// then no sign-in request is ever found.
|
|
662
|
-
|
|
663
|
-
|
|
662
|
+
const req = p.request;
|
|
663
|
+
const existing = requests.get(id);
|
|
664
|
+
if (p.redirectResponse !== undefined && existing) {
|
|
665
|
+
existing.finalUrl = String(req?.url ?? existing.finalUrl);
|
|
666
|
+
}
|
|
667
|
+
else {
|
|
664
668
|
requests.set(id, {
|
|
665
669
|
url: String(req?.url ?? ''),
|
|
670
|
+
finalUrl: String(req?.url ?? ''),
|
|
666
671
|
method: String(req?.method ?? 'GET'),
|
|
667
672
|
type: String(p.type ?? ''),
|
|
668
673
|
status: null,
|
|
@@ -706,15 +711,15 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
706
711
|
const before = await evaluate(INSPECT_EXPR);
|
|
707
712
|
if (!before)
|
|
708
713
|
throw new Error('the page could not be inspected');
|
|
709
|
-
const sameOrigin = (r) => r.
|
|
714
|
+
const sameOrigin = (r) => r.finalUrl.startsWith(`${origin}/`) || r.finalUrl === origin;
|
|
710
715
|
const isData = (r) => r.type === 'XHR' || r.type === 'Fetch';
|
|
711
716
|
const foreignOriginFailures = () => {
|
|
712
717
|
const out = new Set();
|
|
713
718
|
for (const r of requests.values()) {
|
|
714
|
-
if (sameOrigin(r) || !r.failed || !r.
|
|
719
|
+
if (sameOrigin(r) || !r.failed || !r.finalUrl.startsWith('http'))
|
|
715
720
|
continue;
|
|
716
721
|
try {
|
|
717
|
-
out.add(new URL(r.
|
|
722
|
+
out.add(new URL(r.finalUrl).origin);
|
|
718
723
|
}
|
|
719
724
|
catch {
|
|
720
725
|
// unparseable url — nothing to name
|
|
@@ -725,10 +730,11 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
725
730
|
const initiatorOf = (r) => isData(r) ? 'xhr'
|
|
726
731
|
: r.type === 'Document' ? 'document'
|
|
727
732
|
: 'other';
|
|
728
|
-
/** The same-origin request log
|
|
729
|
-
*
|
|
730
|
-
*
|
|
731
|
-
*
|
|
733
|
+
/** The same-origin request log. `postSeq` is where the authenticated half
|
|
734
|
+
* begins — Infinity while no submit has happened — so everything before it is
|
|
735
|
+
* 'pre'; the sign-in request itself is 'auth', not 'post'. The boundary is the
|
|
736
|
+
* sign-in request, not the submit: a CSRF token or a beacon the submit fires
|
|
737
|
+
* BEFORE the login is not evidence about the authenticated client. */
|
|
732
738
|
const sessionLog = (authId, postSeq) => [...requests]
|
|
733
739
|
.filter(([, r]) => sameOrigin(r))
|
|
734
740
|
.map(([id, r]) => ({
|
|
@@ -759,6 +765,7 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
759
765
|
const unsubmitted = (over) => facts(sessionLog(null, Number.POSITIVE_INFINITY), over);
|
|
760
766
|
if (!before.hasPassword || credentials === null)
|
|
761
767
|
return judge(unsubmitted({}));
|
|
768
|
+
const fillSeq = nextSeq;
|
|
762
769
|
const filled = await evaluate(fillExpr(credentials.identifier, credentials.password));
|
|
763
770
|
if (!filled?.ok)
|
|
764
771
|
return judge(unsubmitted({ submitted: false }));
|
|
@@ -784,6 +791,18 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
784
791
|
break;
|
|
785
792
|
}
|
|
786
793
|
}
|
|
794
|
+
// Nothing after the submit: a form that submits from the fill's own input
|
|
795
|
+
// events already sent it. Only a NAVIGATION qualifies here — a form submission
|
|
796
|
+
// is one, and the background traffic the fill races (beacons, telemetry) is
|
|
797
|
+
// XHR or fetch, never a document.
|
|
798
|
+
if (authId === null) {
|
|
799
|
+
for (const [id, r] of requests) {
|
|
800
|
+
if (r.seq >= fillSeq && sameOrigin(r) && r.method !== 'GET' && r.type === 'Document') {
|
|
801
|
+
authId = id;
|
|
802
|
+
break;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
787
806
|
const authReq = authId === null ? null : requests.get(authId);
|
|
788
807
|
const now = await evaluate(INSPECT_EXPR);
|
|
789
808
|
const domJudgment = judgeRenderedDom(now?.html ?? '');
|
|
@@ -805,7 +824,7 @@ export async function driveSession(cdp, { url, credentials, judge, quietMs }) {
|
|
|
805
824
|
lastActivity = Date.now();
|
|
806
825
|
await settle(() => lastActivity, RE_NAV_CAP_MS, quietMs);
|
|
807
826
|
}
|
|
808
|
-
return judge(facts(sessionLog(authId, submitSeq), {
|
|
827
|
+
return judge(facts(sessionLog(authId, authReq?.seq ?? submitSeq), {
|
|
809
828
|
submitted: true,
|
|
810
829
|
foreignOriginFailures: foreignOriginFailures(),
|
|
811
830
|
leftAuthWall,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mjasnikovs/pi-task",
|
|
3
|
-
"version": "0.40.
|
|
3
|
+
"version": "0.40.37",
|
|
4
4
|
"description": "Deterministic task planning and spec-orchestration for local models — crash-safe /task pipelines with verify/enforce gates, a real-time remote web view, and web/docs/fetch/worker subagent tools.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|