Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/server/src/capsule/causal-summary.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { EventType, PerfMetric, isDevToolingUrl, type ReticleEvent } from '@reticlehq/core';
import { routeOfEvent } from '../events/route-of-event.js';

/**
* The causal summary (Tier 1) — the bounded ~50–100 token block on EVERY act, green included: what the
Expand Down Expand Up @@ -205,7 +206,7 @@ export function causalSummary(
break;
}
case EventType.ROUTE_CHANGE:
if ('string' === typeof data['pathname']) route = data['pathname'];
route = routeOfEvent(event).routePath;
break;
case EventType.SIGNAL:
pushUnique(signals, data['name']);
Expand Down
20 changes: 12 additions & 8 deletions packages/server/src/events/predicate-route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
* app is right now — and keeping that reconciliation in one place is what makes it readable.
*/
import { EventType, PredicateKind, type ReticleEvent } from '@reticlehq/core';
import { str, type EvalResult, type Predicate } from './predicate-eval.js';

import { type EvalResult, type Predicate } from './predicate-eval.js';
import { routeOfEvent } from './route-of-event.js';
/**
* Which fact answered a `route` predicate: a navigation inside the window, or where the app is now.
*
Expand Down Expand Up @@ -71,12 +71,16 @@ export function evalRoute(
const last = routes.at(-1);
const reading: RouteReading | undefined =
last !== undefined
? {
pathname: str(last.data['pathname']) ?? str(last.data['to']) ?? '',
full: `${str(last.data['pathname']) ?? str(last.data['to']) ?? ''}${str(last.data['search']) ?? ''}${str(last.data['hash']) ?? ''}`,
decidedBy: RouteDecidedBy.CHANGE,
data: { ...last.data, decidedBy: RouteDecidedBy.CHANGE },
}
? (() => {
const route = routeOfEvent(last);

return {
pathname: route.routePath,
full: route.full,
decidedBy: RouteDecidedBy.CHANGE,
data: { ...last.data, decidedBy: RouteDecidedBy.CHANGE },
};
})()
: currentUrl === undefined || 0 === currentUrl.length
? undefined
: readCurrentRoute(currentUrl);
Expand Down
30 changes: 30 additions & 0 deletions packages/server/src/events/route-of-event.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { type ReticleEvent } from '@reticlehq/core'; //Bring me the event definitions from Reticle's core package
import { str } from './predicate-eval.js';

export interface RouteEventReading {
//blueprint of how my RouteEventReading would look like
routePath: string;
docPath: string;
hash: string;
search: string;
full: string;
}
//Create a function called routeOfEvent. It accepts one route-change event as input,
// and it will return route information in the form of routePath, docPath, hash, search, and full
export function routeOfEvent(event: ReticleEvent): RouteEventReading {
const pathname = str(event.data['pathname']) ?? str(event.data['to']) ?? '';
const search = str(event.data['search']) ?? '';
const hash = str(event.data['hash']) ?? '';

const docPath = pathname;
const routePath = hash.startsWith('#/') ? hash.slice(1) : pathname;
const full = `${docPath}${search}${hash}`;

return {
routePath,
docPath,
hash,
search,
full,
};
}
5 changes: 3 additions & 2 deletions packages/server/src/flows/flow-replay-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
type FlowStepResult,
type ReticleEvent,
} from '@reticlehq/core';

import { routeOfEvent } from '../events/route-of-event.js';
import { asString } from '../tools/tools-helpers.js';
import { replayFlow } from './flow-replay.js';
import { assertSuccess, dynamicTestids, successLabel, SUCCESS_STEP_TOOL } from './flow-success.js';
Expand Down Expand Up @@ -122,8 +124,7 @@ export function startPathMismatchHint(
if (startPath === undefined || 0 === startPath.length) return undefined;
const routes = session.eventsSince(0).filter((e) => e.type === EventType.ROUTE_CHANGE);
const last = routes.at(-1);
const data = last?.data ?? {};
const current = asString(data['pathname']) ?? asString(data['to']);
const current = last === undefined ? undefined : routeOfEvent(last).full;
if (current === undefined || current === startPath) return undefined;
return `this flow's journey starts on ${startPath} but the tab is on ${current} — navigate there (reticle_navigate { url: "${startPath}" }), then replay`;
}
Expand Down
11 changes: 5 additions & 6 deletions packages/server/src/flows/flow-replay.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { span } from '../trace.js';
import { routeOfEvent } from '../events/route-of-event.js';
import {
AnchorKind,
DriftReason,
Expand Down Expand Up @@ -273,9 +274,8 @@ function currentRoute(session: FlowReplaySession): string | undefined {
const routes = session.eventsSince(0).filter((e) => e.type === EventType.ROUTE_CHANGE);
const last = routes.at(-1);
if (last === undefined) return undefined;
const data = last.data ?? {};
const pathname = asString(data['pathname']) ?? asString(data['to']);
return pathname !== undefined && pathname.length > 0 ? pathname : undefined;
const route = routeOfEvent(last);
return route.routePath.length > 0 ? route.routePath : undefined;
}

/** Pathname only (drop origin + query) so a net URL stays terse in the journey. */
Expand All @@ -296,9 +296,8 @@ function summarizeConsequence(events: ReticleEvent[]): string | undefined {
const parts: string[] = [];
const lastRoute = events.filter((e) => e.type === EventType.ROUTE_CHANGE).at(-1);
if (lastRoute !== undefined) {
const data = lastRoute.data ?? {};
const to = asString(data['pathname']) ?? asString(data['to']);
if (to !== undefined && to.length > 0) parts.push(`→ ${to}`);
const route = routeOfEvent(lastRoute);
if (route.routePath.length > 0) parts.push(`→ ${route.routePath}`);
}
const signals = new Set<string>();
for (const e of events) {
Expand Down
4 changes: 2 additions & 2 deletions packages/server/src/oracles/propose-consequences.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { EventType, type ReticleEvent, PredicateKind } from '@reticlehq/core';

import { routeOfEvent } from '../events/route-of-event.js';
/**
* Self-generating oracles, v1. Given the window a recording captured, propose ranked mustHold
* predicates — the practical answer to "you recorded a flow, now what should it assert?". Ranking
Expand Down Expand Up @@ -87,7 +87,7 @@ export function proposeConsequences(events: readonly ReticleEvent[]): ProposedCo
break;
}
case EventType.ROUTE_CHANGE: {
const to = data['pathname'];
const to = routeOfEvent(event).routePath;
if ('string' === typeof to) {
add(`route:${to}`, {
predicate: { kind: PredicateKind.ROUTE, to },
Expand Down
Loading