tapline-host 1.4.0 → 1.5.0
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/dist/audit.d.ts +2 -0
- package/dist/audit.js +1 -1
- package/dist/audit.js.map +1 -1
- package/dist/cli.js +4 -0
- package/dist/cli.js.map +1 -1
- package/dist/format.d.ts +4 -0
- package/dist/format.js +61 -20
- package/dist/format.js.map +1 -1
- package/dist/images.d.ts +27 -0
- package/dist/images.js +50 -0
- package/dist/images.js.map +1 -1
- package/dist/journey.d.ts +259 -0
- package/dist/journey.js +336 -0
- package/dist/journey.js.map +1 -0
- package/dist/journeyexport.d.ts +58 -0
- package/dist/journeyexport.js +318 -0
- package/dist/journeyexport.js.map +1 -0
- package/dist/journeygif.d.ts +62 -0
- package/dist/journeygif.js +192 -0
- package/dist/journeygif.js.map +1 -0
- package/dist/journeyreport.d.ts +202 -0
- package/dist/journeyreport.js +664 -0
- package/dist/journeyreport.js.map +1 -0
- package/dist/mcp.d.ts +1 -0
- package/dist/mcp.js +27 -1
- package/dist/mcp.js.map +1 -1
- package/dist/media.d.ts +86 -0
- package/dist/media.js +244 -0
- package/dist/media.js.map +1 -0
- package/dist/protocol.d.ts +4 -0
- package/dist/protocol.js +2 -0
- package/dist/protocol.js.map +1 -1
- package/dist/run.js +1 -1
- package/dist/run.js.map +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/server.js +8 -0
- package/dist/server.js.map +1 -1
- package/dist/tool-text-data.d.ts +3 -0
- package/dist/tool-text-data.js +3 -0
- package/dist/tool-text-data.js.map +1 -1
- package/dist/tools.d.ts +213 -0
- package/dist/tools.js +1075 -28
- package/dist/tools.js.map +1 -1
- package/dist/uxcheck.d.ts +102 -0
- package/dist/uxcheck.js +128 -0
- package/dist/uxcheck.js.map +1 -0
- package/package.json +2 -1
- package/skills/tapline/SKILL.md +7 -0
- package/skills/tapline/references/personas.md +45 -0
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* `journey` (AGENT-TOOLS 1.12 §17.1): the state of the one journey an agent has running, and what the host measures
|
|
4
|
+
* from the agent's calls. This module holds no I/O. `TaplineTools` feeds it each call's outcome and each full list
|
|
5
|
+
* the agent was given; the report writer (§17.5) and the stress moments (§17.4) read the same state.
|
|
6
|
+
*/
|
|
7
|
+
export declare const TEXT_SIZES: readonly ["xs", "s", "m", "l", "xl", "xxl", "xxxl", "ax1", "ax2", "ax3", "ax4", "ax5", "system"];
|
|
8
|
+
export declare const NETWORK_CONDITIONS: readonly ["offline", "3g", "lossy"];
|
|
9
|
+
/** The 1.4 conditions a journey may start under. */
|
|
10
|
+
export declare const conditionsSchema: z.ZodObject<{
|
|
11
|
+
language: z.ZodOptional<z.ZodString>;
|
|
12
|
+
region: z.ZodOptional<z.ZodString>;
|
|
13
|
+
text_size: z.ZodOptional<z.ZodEnum<{
|
|
14
|
+
s: "s";
|
|
15
|
+
m: "m";
|
|
16
|
+
xs: "xs";
|
|
17
|
+
l: "l";
|
|
18
|
+
xl: "xl";
|
|
19
|
+
xxl: "xxl";
|
|
20
|
+
xxxl: "xxxl";
|
|
21
|
+
ax1: "ax1";
|
|
22
|
+
ax2: "ax2";
|
|
23
|
+
ax3: "ax3";
|
|
24
|
+
ax4: "ax4";
|
|
25
|
+
ax5: "ax5";
|
|
26
|
+
system: "system";
|
|
27
|
+
}>>;
|
|
28
|
+
network: z.ZodOptional<z.ZodEnum<{
|
|
29
|
+
offline: "offline";
|
|
30
|
+
"3g": "3g";
|
|
31
|
+
lossy: "lossy";
|
|
32
|
+
}>>;
|
|
33
|
+
}, z.core.$strict>;
|
|
34
|
+
export type Conditions = z.infer<typeof conditionsSchema>;
|
|
35
|
+
/** Where a finished journey's report goes, when the user asked for it (§17.5). */
|
|
36
|
+
export declare const exportSchema: z.ZodObject<{
|
|
37
|
+
to: z.ZodEnum<{
|
|
38
|
+
pr: "pr";
|
|
39
|
+
issue: "issue";
|
|
40
|
+
}>;
|
|
41
|
+
repo: z.ZodString;
|
|
42
|
+
pr: z.ZodOptional<z.ZodNumber>;
|
|
43
|
+
confirm: z.ZodOptional<z.ZodBoolean>;
|
|
44
|
+
public: z.ZodOptional<z.ZodBoolean>;
|
|
45
|
+
fork: z.ZodOptional<z.ZodBoolean>;
|
|
46
|
+
}, z.core.$strict>;
|
|
47
|
+
export type JourneyExport = z.infer<typeof exportSchema>;
|
|
48
|
+
/** A stress moment (§17.4). Only the shape is built; the moments come with their own module. */
|
|
49
|
+
export declare const stressSchema: z.ZodObject<{
|
|
50
|
+
kind: z.ZodEnum<{
|
|
51
|
+
network: "network";
|
|
52
|
+
background: "background";
|
|
53
|
+
double_tap: "double_tap";
|
|
54
|
+
rotate: "rotate";
|
|
55
|
+
relaunch: "relaunch";
|
|
56
|
+
}>;
|
|
57
|
+
mode: z.ZodOptional<z.ZodEnum<{
|
|
58
|
+
offline: "offline";
|
|
59
|
+
"3g": "3g";
|
|
60
|
+
lossy: "lossy";
|
|
61
|
+
normal: "normal";
|
|
62
|
+
}>>;
|
|
63
|
+
target: z.ZodOptional<z.ZodObject<{
|
|
64
|
+
ref: z.ZodOptional<z.ZodString>;
|
|
65
|
+
text: z.ZodOptional<z.ZodString>;
|
|
66
|
+
x: z.ZodOptional<z.ZodNumber>;
|
|
67
|
+
y: z.ZodOptional<z.ZodNumber>;
|
|
68
|
+
}, z.core.$strict>>;
|
|
69
|
+
}, z.core.$strict>;
|
|
70
|
+
export type Stress = z.infer<typeof stressSchema>;
|
|
71
|
+
/** What must still be there after a stress moment (§17.4). */
|
|
72
|
+
export declare const survivesSchema: z.ZodObject<{
|
|
73
|
+
text: z.ZodOptional<z.ZodString>;
|
|
74
|
+
goal_step: z.ZodOptional<z.ZodString>;
|
|
75
|
+
}, z.core.$strict>;
|
|
76
|
+
export type Survives = z.infer<typeof survivesSchema>;
|
|
77
|
+
export declare const EYES: readonly ["user", "agent"];
|
|
78
|
+
export type Eyes = (typeof EYES)[number];
|
|
79
|
+
/** Shortcuts a journey may name in `allow` besides app commands. */
|
|
80
|
+
export declare const OPEN_URL = "open_url";
|
|
81
|
+
/** One screen the agent was shown in full: the first full list of a route, kept for the report. */
|
|
82
|
+
export interface JourneyScreen {
|
|
83
|
+
/** 1-based, in the order the journey first reached them. */
|
|
84
|
+
n: number;
|
|
85
|
+
/** The route names (`Route:` line), or `[]` when the app has no router. */
|
|
86
|
+
route: string[];
|
|
87
|
+
/** The first full list the agent was given for this screen (the text, as answered). */
|
|
88
|
+
firstList: string;
|
|
89
|
+
/** How many times the journey entered this screen. */
|
|
90
|
+
visits: number;
|
|
91
|
+
/** Clock time of the first entry, ms. */
|
|
92
|
+
at: number;
|
|
93
|
+
}
|
|
94
|
+
/** What the measures counted a call as, for the report's findings. */
|
|
95
|
+
export type StepFlag = "wrong_turn" | "dead_end" | "error" | "crash";
|
|
96
|
+
/** One call the agent made during the journey: the list the report's path and the GIF frames are built from. */
|
|
97
|
+
export interface JourneyStep {
|
|
98
|
+
/** Set when the call was a wrong turn, a dead end, an error or a crash. */
|
|
99
|
+
flags?: StepFlag[];
|
|
100
|
+
n: number;
|
|
101
|
+
tool: string;
|
|
102
|
+
/** The target as the agent wrote it, in words (`"Save"`, `e3`, `120,300`), when it gave one. */
|
|
103
|
+
target?: string;
|
|
104
|
+
ok: boolean;
|
|
105
|
+
code?: string;
|
|
106
|
+
/** The first line of the answer. */
|
|
107
|
+
said: string;
|
|
108
|
+
/** Clock time the call began, ms, and how long it took. */
|
|
109
|
+
at: number;
|
|
110
|
+
ms: number;
|
|
111
|
+
/** Index into `screens` (1-based `n`) of the screen the call ended on. */
|
|
112
|
+
screen: number | undefined;
|
|
113
|
+
}
|
|
114
|
+
export interface JourneyMeasures {
|
|
115
|
+
taps: number;
|
|
116
|
+
typing: number;
|
|
117
|
+
scrolls: number;
|
|
118
|
+
/** Times a screen was entered (the same screen twice counts twice). */
|
|
119
|
+
screensEntered: number;
|
|
120
|
+
wrongTurns: number;
|
|
121
|
+
deadEnds: number;
|
|
122
|
+
errors: number;
|
|
123
|
+
hesitations: number;
|
|
124
|
+
/** Time spent waiting, ms: `wait`, `wait_for` and the `Settled in` time of actions. */
|
|
125
|
+
waitMs: number;
|
|
126
|
+
}
|
|
127
|
+
/** A shortcut a person doesn't have, that `allow` let through. */
|
|
128
|
+
export interface UsedShortcut {
|
|
129
|
+
tool: "open_url" | "app_command";
|
|
130
|
+
/** The url, or the command's name. */
|
|
131
|
+
what: string;
|
|
132
|
+
}
|
|
133
|
+
/** A condition as it was applied, and what undoing it did. */
|
|
134
|
+
export interface ConditionRecord {
|
|
135
|
+
name: keyof Conditions;
|
|
136
|
+
value: string;
|
|
137
|
+
applied: boolean;
|
|
138
|
+
/** Why it wasn't applied. */
|
|
139
|
+
failure?: string;
|
|
140
|
+
/** What the app said the value was before (language, region), when it said. */
|
|
141
|
+
previous?: string;
|
|
142
|
+
undone?: boolean;
|
|
143
|
+
/** What undoing it did or why it didn't: a line for the stop answer. */
|
|
144
|
+
undo?: string;
|
|
145
|
+
}
|
|
146
|
+
/** One stress moment (§17.4): what was done and whether what had to survive did. */
|
|
147
|
+
export interface StressResult {
|
|
148
|
+
kind: Stress["kind"];
|
|
149
|
+
/** The answer's sentence, `Stress: background; it survived: …`. */
|
|
150
|
+
said: string;
|
|
151
|
+
/** null: nothing was asked to survive, so nothing was checked. */
|
|
152
|
+
survived: boolean | null;
|
|
153
|
+
/** The count of steps made before it, to find its screen. */
|
|
154
|
+
afterStep: number;
|
|
155
|
+
at: number;
|
|
156
|
+
}
|
|
157
|
+
export interface JourneyState {
|
|
158
|
+
goal: string;
|
|
159
|
+
persona: string | undefined;
|
|
160
|
+
conditions: Conditions;
|
|
161
|
+
allow: string[];
|
|
162
|
+
/** `"user"` until the agent turns it off; `eyesSwitchedAt` says when (the report says so). */
|
|
163
|
+
eyes: Eyes;
|
|
164
|
+
startedAt: number;
|
|
165
|
+
eyesSwitchedAt?: number;
|
|
166
|
+
endedAt?: number;
|
|
167
|
+
reached?: boolean;
|
|
168
|
+
why?: string;
|
|
169
|
+
/** `taps` at the moment the goal was reached; null when it wasn't. */
|
|
170
|
+
tapsToGoal: number | null;
|
|
171
|
+
measures: JourneyMeasures;
|
|
172
|
+
screens: JourneyScreen[];
|
|
173
|
+
steps: JourneyStep[];
|
|
174
|
+
shortcuts: UsedShortcut[];
|
|
175
|
+
conditionRecords: ConditionRecord[];
|
|
176
|
+
/** The stress moments (§17.4) and how the app took them. */
|
|
177
|
+
stress: StressResult[];
|
|
178
|
+
/** A network condition a stress moment set and that is still on: undone at the stop, report or not. */
|
|
179
|
+
networkStress: boolean;
|
|
180
|
+
/** The route key of the screen the agent is on now. */
|
|
181
|
+
currentScreen: number | undefined;
|
|
182
|
+
}
|
|
183
|
+
/** What `record` is told of one finished call. */
|
|
184
|
+
export interface CallOutcome {
|
|
185
|
+
tool: string;
|
|
186
|
+
target?: string;
|
|
187
|
+
ok: boolean;
|
|
188
|
+
code?: string;
|
|
189
|
+
/** The whole answer's text. */
|
|
190
|
+
text: string;
|
|
191
|
+
at: number;
|
|
192
|
+
ms: number;
|
|
193
|
+
}
|
|
194
|
+
/** The counters read before a call, since the call's own list may start a new screen. */
|
|
195
|
+
export interface Pre {
|
|
196
|
+
screen: number | undefined;
|
|
197
|
+
actionsOnScreen: number;
|
|
198
|
+
/** The screen was entered during the journey (not the one it started on). */
|
|
199
|
+
entered: boolean;
|
|
200
|
+
}
|
|
201
|
+
/** Tools that only look: two or more in a row with no action in between is a hesitation. */
|
|
202
|
+
export declare const READ_TOOLS_FOR_HESITATION: ReadonlySet<string>;
|
|
203
|
+
export declare class Journey {
|
|
204
|
+
private readonly clock;
|
|
205
|
+
readonly state: JourneyState;
|
|
206
|
+
private actionsOnScreen;
|
|
207
|
+
private readStreak;
|
|
208
|
+
private readonly listeners;
|
|
209
|
+
constructor(init: {
|
|
210
|
+
goal: string;
|
|
211
|
+
persona?: string;
|
|
212
|
+
conditions?: Conditions;
|
|
213
|
+
allow?: string[];
|
|
214
|
+
eyes?: Eyes;
|
|
215
|
+
}, clock: () => number);
|
|
216
|
+
get userEyes(): boolean;
|
|
217
|
+
/** The report's (and the GIF's) hook: told of every counted call as it is recorded. */
|
|
218
|
+
onStep(listener: (step: JourneyStep) => void): void;
|
|
219
|
+
/** `allow` names this shortcut (`open_url`, or an app command's name). */
|
|
220
|
+
allows(name: string): boolean;
|
|
221
|
+
noteShortcut(shortcut: UsedShortcut): void;
|
|
222
|
+
pre(): Pre;
|
|
223
|
+
/**
|
|
224
|
+
* The agent was given a full list. `fromAction`: it came with an action's answer (most of the screen changed), not
|
|
225
|
+
* from `look`. A new screen is a different route, or, in an app with no router, a full list after an action.
|
|
226
|
+
*/
|
|
227
|
+
noteFullList(list: {
|
|
228
|
+
route: string[];
|
|
229
|
+
text: string;
|
|
230
|
+
fromAction: boolean;
|
|
231
|
+
}): void;
|
|
232
|
+
/** The agent's call has been answered: the measures. */
|
|
233
|
+
record(outcome: CallOutcome, pre: Pre): void;
|
|
234
|
+
/** `stop`: fixes the end and the taps to the goal. */
|
|
235
|
+
finish(reached: boolean, why: string | undefined): JourneyState;
|
|
236
|
+
switchEyes(): void;
|
|
237
|
+
}
|
|
238
|
+
/** `52 s`, `1 min 52 s`, `2 min`. */
|
|
239
|
+
export declare function formatDuration(ms: number): string;
|
|
240
|
+
export declare function personaWords(state: Pick<JourneyState, "persona">): string;
|
|
241
|
+
/** The first line of the stop answer (§17.5): `Journey "…" as …: reached in 9 taps, 1 min 52 s (34 s waiting), 2 wrong turns, 3 hesitations.` */
|
|
242
|
+
export declare function summaryLine(state: JourneyState): string;
|
|
243
|
+
/** The lines that follow the summary: what else was hit, what was used, what was and wasn't undone. */
|
|
244
|
+
export declare function summaryNotes(state: JourneyState): string[];
|
|
245
|
+
/** Strips the ids a user's eyes must not show (` id=save`) from text the SDK composed (error messages, `Closest:` lists). */
|
|
246
|
+
export declare function withoutIds(text: string): string;
|
|
247
|
+
/**
|
|
248
|
+
* Strips what a field holds (` value="…"`, ` placeholder="…"`, a quoted string with its escapes, or a bare number or
|
|
249
|
+
* word) from a step's sentence: what was typed may be private, and the sentence goes into the report and the export.
|
|
250
|
+
*/
|
|
251
|
+
export declare function withoutFieldText(text: string): string;
|
|
252
|
+
/**
|
|
253
|
+
* Cuts what a link may carry that isn't the place it leads (a sign-in token, a reset code, a session): the query and
|
|
254
|
+
* the fragment become `?…` and `#…`, a user and password before the host go, and a token-like path segment becomes
|
|
255
|
+
* `…`. The scheme, host and the rest of the path stay, so the report still says where the link went.
|
|
256
|
+
*/
|
|
257
|
+
export declare function withoutUrlSecrets(text: string): string;
|
|
258
|
+
/** The answer to `id` or `label` as a target in a journey (§17.1). */
|
|
259
|
+
export declare const IDS_HIDDEN = "Error bad_params: in a journey, ids and labels are hidden; use a ref or the visible text";
|
package/dist/journey.js
ADDED
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/**
|
|
3
|
+
* `journey` (AGENT-TOOLS 1.12 §17.1): the state of the one journey an agent has running, and what the host measures
|
|
4
|
+
* from the agent's calls. This module holds no I/O. `TaplineTools` feeds it each call's outcome and each full list
|
|
5
|
+
* the agent was given; the report writer (§17.5) and the stress moments (§17.4) read the same state.
|
|
6
|
+
*/
|
|
7
|
+
// ---- input ------------------------------------------------------------------
|
|
8
|
+
export const TEXT_SIZES = ["xs", "s", "m", "l", "xl", "xxl", "xxxl", "ax1", "ax2", "ax3", "ax4", "ax5", "system"];
|
|
9
|
+
export const NETWORK_CONDITIONS = ["offline", "3g", "lossy"];
|
|
10
|
+
/** The 1.4 conditions a journey may start under. */
|
|
11
|
+
export const conditionsSchema = z
|
|
12
|
+
.object({
|
|
13
|
+
language: z.string().min(2).max(35).optional().describe('BCP 47 code, e.g. "ar"'),
|
|
14
|
+
region: z.string().length(2).optional().describe('ISO 3166 country code, e.g. "QA"'),
|
|
15
|
+
text_size: z.enum(TEXT_SIZES).optional().describe("xs to xxxl, ax1 to ax5"),
|
|
16
|
+
network: z.enum(NETWORK_CONDITIONS).optional().describe("offline, 3g or lossy"),
|
|
17
|
+
})
|
|
18
|
+
.strict();
|
|
19
|
+
/** Where a finished journey's report goes, when the user asked for it (§17.5). */
|
|
20
|
+
export const exportSchema = z
|
|
21
|
+
.object({
|
|
22
|
+
to: z.enum(["pr", "issue"]),
|
|
23
|
+
repo: z.string().min(3).max(140),
|
|
24
|
+
pr: z.number().int().min(1).optional(),
|
|
25
|
+
confirm: z.boolean().optional().describe("true: your user asked for this export (it writes to their GitHub)"),
|
|
26
|
+
public: z.boolean().optional().describe("true: the repository is public and the report may be written there"),
|
|
27
|
+
fork: z.boolean().optional().describe("With to: pr: true when the pull request's branch is in another repository (a fork) and the report may be written there"),
|
|
28
|
+
})
|
|
29
|
+
.strict()
|
|
30
|
+
.superRefine((value, ctx) => {
|
|
31
|
+
if (value.to === "issue" && value.fork !== undefined)
|
|
32
|
+
ctx.addIssue({ code: "custom", message: 'export to "issue" takes no fork.' });
|
|
33
|
+
if (value.to === "pr" && value.pr === undefined)
|
|
34
|
+
ctx.addIssue({ code: "custom", message: 'export to "pr" needs the pull request number: pr.' });
|
|
35
|
+
if (value.to === "issue" && value.pr !== undefined)
|
|
36
|
+
ctx.addIssue({ code: "custom", message: 'export to "issue" takes no pr.' });
|
|
37
|
+
});
|
|
38
|
+
/** A stress moment (§17.4). Only the shape is built; the moments come with their own module. */
|
|
39
|
+
export const stressSchema = z
|
|
40
|
+
.object({
|
|
41
|
+
kind: z.enum(["background", "network", "double_tap", "rotate", "relaunch"]),
|
|
42
|
+
mode: z.enum(["offline", "3g", "lossy", "normal"]).optional().describe("With network: the condition that starts mid-flow"),
|
|
43
|
+
target: z
|
|
44
|
+
.object({ ref: z.string().optional(), text: z.string().optional(), x: z.number().optional(), y: z.number().optional() })
|
|
45
|
+
.strict()
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("With double_tap: what to touch twice"),
|
|
48
|
+
})
|
|
49
|
+
.strict();
|
|
50
|
+
/** What must still be there after a stress moment (§17.4). */
|
|
51
|
+
export const survivesSchema = z.object({ text: z.string().optional(), goal_step: z.string().optional() }).strict();
|
|
52
|
+
export const EYES = ["user", "agent"];
|
|
53
|
+
/** Shortcuts a journey may name in `allow` besides app commands. */
|
|
54
|
+
export const OPEN_URL = "open_url";
|
|
55
|
+
const ACTION_TOOLS = new Set(["tap", "long_press", "type_text", "toggle"]);
|
|
56
|
+
const TAP_TOOLS = new Set(["tap", "long_press", "toggle"]);
|
|
57
|
+
const SCROLL_TOOLS = new Set(["scroll", "swipe"]);
|
|
58
|
+
const WAIT_TOOLS = new Set(["wait", "wait_for"]);
|
|
59
|
+
/** Tools that only look: two or more in a row with no action in between is a hesitation. */
|
|
60
|
+
export const READ_TOOLS_FOR_HESITATION = new Set(["look", "check_layout", "audit", "inspect", "logs", "crash", "compare_screen", "filmstrip", "ux_check"]);
|
|
61
|
+
const SETTLED = /^Settled in (\d+(?:\.\d+)?) s\.$/m;
|
|
62
|
+
const CRASH_NOTE = /^Note: the app (?:crashed|disconnected)/m;
|
|
63
|
+
export class Journey {
|
|
64
|
+
clock;
|
|
65
|
+
state;
|
|
66
|
+
actionsOnScreen = 0;
|
|
67
|
+
readStreak = 0;
|
|
68
|
+
listeners = [];
|
|
69
|
+
constructor(init, clock) {
|
|
70
|
+
this.clock = clock;
|
|
71
|
+
this.state = {
|
|
72
|
+
goal: init.goal,
|
|
73
|
+
persona: init.persona,
|
|
74
|
+
conditions: init.conditions ?? {},
|
|
75
|
+
allow: init.allow ?? [],
|
|
76
|
+
eyes: init.eyes ?? "user",
|
|
77
|
+
startedAt: clock(),
|
|
78
|
+
tapsToGoal: null,
|
|
79
|
+
measures: { taps: 0, typing: 0, scrolls: 0, screensEntered: 0, wrongTurns: 0, deadEnds: 0, errors: 0, hesitations: 0, waitMs: 0 },
|
|
80
|
+
screens: [],
|
|
81
|
+
steps: [],
|
|
82
|
+
shortcuts: [],
|
|
83
|
+
conditionRecords: [],
|
|
84
|
+
stress: [],
|
|
85
|
+
networkStress: false,
|
|
86
|
+
currentScreen: undefined,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
get userEyes() {
|
|
90
|
+
return this.state.eyes === "user";
|
|
91
|
+
}
|
|
92
|
+
/** The report's (and the GIF's) hook: told of every counted call as it is recorded. */
|
|
93
|
+
onStep(listener) {
|
|
94
|
+
this.listeners.push(listener);
|
|
95
|
+
}
|
|
96
|
+
/** `allow` names this shortcut (`open_url`, or an app command's name). */
|
|
97
|
+
allows(name) {
|
|
98
|
+
return this.state.allow.includes(name);
|
|
99
|
+
}
|
|
100
|
+
noteShortcut(shortcut) {
|
|
101
|
+
this.state.shortcuts.push({ ...shortcut, what: withoutUrlSecrets(shortcut.what) });
|
|
102
|
+
}
|
|
103
|
+
pre() {
|
|
104
|
+
return { screen: this.state.currentScreen, actionsOnScreen: this.actionsOnScreen, entered: this.state.measures.screensEntered > 1 };
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* The agent was given a full list. `fromAction`: it came with an action's answer (most of the screen changed), not
|
|
108
|
+
* from `look`. A new screen is a different route, or, in an app with no router, a full list after an action.
|
|
109
|
+
*/
|
|
110
|
+
noteFullList(list) {
|
|
111
|
+
const key = list.route.join(" › ");
|
|
112
|
+
const current = this.state.currentScreen === undefined ? undefined : this.state.screens[this.state.currentScreen - 1];
|
|
113
|
+
const same = current !== undefined && current.route.join(" › ") === key && !(list.route.length === 0 && list.fromAction);
|
|
114
|
+
if (same)
|
|
115
|
+
return;
|
|
116
|
+
const known = list.route.length === 0 ? undefined : this.state.screens.find((s) => s.route.join(" › ") === key);
|
|
117
|
+
this.state.measures.screensEntered++;
|
|
118
|
+
this.actionsOnScreen = 0;
|
|
119
|
+
if (known !== undefined) {
|
|
120
|
+
known.visits++;
|
|
121
|
+
this.state.currentScreen = known.n;
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
const n = this.state.screens.length + 1;
|
|
125
|
+
this.state.screens.push({ n, route: list.route, firstList: list.text, visits: 1, at: this.clock() });
|
|
126
|
+
this.state.currentScreen = n;
|
|
127
|
+
}
|
|
128
|
+
/** The agent's call has been answered: the measures. */
|
|
129
|
+
record(outcome, pre) {
|
|
130
|
+
const m = this.state.measures;
|
|
131
|
+
const { tool, ok, code } = outcome;
|
|
132
|
+
const screenChanged = this.state.currentScreen !== pre.screen;
|
|
133
|
+
if (WAIT_TOOLS.has(tool))
|
|
134
|
+
m.waitMs += outcome.ms;
|
|
135
|
+
else {
|
|
136
|
+
const settled = SETTLED.exec(outcome.text);
|
|
137
|
+
if (settled?.[1] !== undefined)
|
|
138
|
+
m.waitMs += Math.round(Number(settled[1]) * 1000);
|
|
139
|
+
}
|
|
140
|
+
if (ok) {
|
|
141
|
+
if (TAP_TOOLS.has(tool))
|
|
142
|
+
m.taps++;
|
|
143
|
+
if (tool === "type_text")
|
|
144
|
+
m.typing++;
|
|
145
|
+
if (SCROLL_TOOLS.has(tool))
|
|
146
|
+
m.scrolls++;
|
|
147
|
+
}
|
|
148
|
+
if (ACTION_TOOLS.has(tool) && ok && !screenChanged)
|
|
149
|
+
this.actionsOnScreen++;
|
|
150
|
+
const flags = [];
|
|
151
|
+
// A screen entered and left by `back` with no action on it (a sheet that closes is no screen).
|
|
152
|
+
if (tool === "back" && ok && !/^Closed the sheet\./.test(outcome.text) && pre.entered && pre.actionsOnScreen === 0) {
|
|
153
|
+
m.wrongTurns++;
|
|
154
|
+
flags.push("wrong_turn");
|
|
155
|
+
}
|
|
156
|
+
if (code === "not_actionable" || code === "not_allowed") {
|
|
157
|
+
m.deadEnds++;
|
|
158
|
+
flags.push("dead_end");
|
|
159
|
+
}
|
|
160
|
+
if (code === "not_found" || CRASH_NOTE.test(outcome.text)) {
|
|
161
|
+
m.errors++;
|
|
162
|
+
flags.push(CRASH_NOTE.test(outcome.text) ? "crash" : "error");
|
|
163
|
+
}
|
|
164
|
+
// Hesitation: a run of two or more reads with no action. One counts at the second read.
|
|
165
|
+
if (READ_TOOLS_FOR_HESITATION.has(tool)) {
|
|
166
|
+
this.readStreak++;
|
|
167
|
+
if (this.readStreak === 2)
|
|
168
|
+
m.hesitations++;
|
|
169
|
+
}
|
|
170
|
+
else if (!WAIT_TOOLS.has(tool)) {
|
|
171
|
+
this.readStreak = 0;
|
|
172
|
+
}
|
|
173
|
+
// What the agent typed is its own business (it may be a password the app hides): the step keeps the sentence without it.
|
|
174
|
+
// The same for what a field holds: a tap or toggle on a filled input prints its value and placeholder too (finding 8).
|
|
175
|
+
// A link may carry a sign-in token (`myapp://login?token=…`): only its scheme, host and path stay.
|
|
176
|
+
const first = withoutUrlSecrets(withoutFieldText((outcome.text.split("\n")[0] ?? "").replace(tool === "type_text" ? / Value is now .*$/ : /(?!)/, "")));
|
|
177
|
+
const step = {
|
|
178
|
+
n: this.state.steps.length + 1,
|
|
179
|
+
tool,
|
|
180
|
+
...(outcome.target !== undefined ? { target: withoutUrlSecrets(outcome.target) } : {}),
|
|
181
|
+
ok,
|
|
182
|
+
...(code !== undefined ? { code } : {}),
|
|
183
|
+
said: first.length > 200 ? `${first.slice(0, 200)}…` : first,
|
|
184
|
+
...(flags.length > 0 ? { flags } : {}),
|
|
185
|
+
at: outcome.at,
|
|
186
|
+
ms: outcome.ms,
|
|
187
|
+
screen: this.state.currentScreen,
|
|
188
|
+
};
|
|
189
|
+
this.state.steps.push(step);
|
|
190
|
+
for (const listener of this.listeners)
|
|
191
|
+
listener(step);
|
|
192
|
+
}
|
|
193
|
+
/** `stop`: fixes the end and the taps to the goal. */
|
|
194
|
+
finish(reached, why) {
|
|
195
|
+
this.state.endedAt = this.clock();
|
|
196
|
+
this.state.reached = reached;
|
|
197
|
+
if (why !== undefined && why.trim() !== "")
|
|
198
|
+
this.state.why = why.trim();
|
|
199
|
+
this.state.tapsToGoal = reached ? this.state.measures.taps : null;
|
|
200
|
+
return this.state;
|
|
201
|
+
}
|
|
202
|
+
switchEyes() {
|
|
203
|
+
this.state.eyes = "agent";
|
|
204
|
+
this.state.eyesSwitchedAt = this.clock();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
// ---- words ------------------------------------------------------------------
|
|
208
|
+
/** `52 s`, `1 min 52 s`, `2 min`. */
|
|
209
|
+
export function formatDuration(ms) {
|
|
210
|
+
const total = Math.max(0, Math.round(ms / 1000));
|
|
211
|
+
const minutes = Math.floor(total / 60);
|
|
212
|
+
const seconds = total % 60;
|
|
213
|
+
if (minutes === 0)
|
|
214
|
+
return `${seconds} s`;
|
|
215
|
+
return seconds === 0 ? `${minutes} min` : `${minutes} min ${seconds} s`;
|
|
216
|
+
}
|
|
217
|
+
function plural(n, one, many = `${one}s`) {
|
|
218
|
+
return `${n} ${n === 1 ? one : many}`;
|
|
219
|
+
}
|
|
220
|
+
export function personaWords(state) {
|
|
221
|
+
return state.persona !== undefined && state.persona.trim() !== "" ? state.persona.trim() : "no persona";
|
|
222
|
+
}
|
|
223
|
+
/** The first line of the stop answer (§17.5): `Journey "…" as …: reached in 9 taps, 1 min 52 s (34 s waiting), 2 wrong turns, 3 hesitations.` */
|
|
224
|
+
export function summaryLine(state) {
|
|
225
|
+
const m = state.measures;
|
|
226
|
+
const elapsed = (state.endedAt ?? state.startedAt) - state.startedAt;
|
|
227
|
+
const numbers = [
|
|
228
|
+
state.reached === true ? `reached in ${plural(state.tapsToGoal ?? m.taps, "tap")}` : `not reached after ${plural(m.taps, "tap")}`,
|
|
229
|
+
`${formatDuration(elapsed)} (${formatDuration(m.waitMs)} waiting)`,
|
|
230
|
+
plural(m.wrongTurns, "wrong turn"),
|
|
231
|
+
plural(m.hesitations, "hesitation"),
|
|
232
|
+
];
|
|
233
|
+
return `Journey "${state.goal}" as ${personaWords(state)}: ${numbers.join(", ")}.`;
|
|
234
|
+
}
|
|
235
|
+
/** The lines that follow the summary: what else was hit, what was used, what was and wasn't undone. */
|
|
236
|
+
export function summaryNotes(state) {
|
|
237
|
+
const m = state.measures;
|
|
238
|
+
const lines = [];
|
|
239
|
+
const hit = [];
|
|
240
|
+
if (m.deadEnds > 0)
|
|
241
|
+
hit.push(plural(m.deadEnds, "dead end"));
|
|
242
|
+
if (m.errors > 0)
|
|
243
|
+
hit.push(plural(m.errors, "error hit", "errors hit"));
|
|
244
|
+
if (hit.length > 0)
|
|
245
|
+
lines.push(`Also: ${hit.join(", ")}.`);
|
|
246
|
+
if (state.why !== undefined)
|
|
247
|
+
lines.push(`Why: ${state.why}`);
|
|
248
|
+
if (state.eyesSwitchedAt !== undefined)
|
|
249
|
+
lines.push("Eyes: the agent's, not a user's, from the moment it turned them off.");
|
|
250
|
+
if (state.shortcuts.length > 0) {
|
|
251
|
+
lines.push(`Shortcuts used (a person doesn't have these): ${state.shortcuts.map((s) => `${s.tool} ${JSON.stringify(s.what)}`).join(", ")}.`);
|
|
252
|
+
}
|
|
253
|
+
for (const record of state.conditionRecords)
|
|
254
|
+
if (record.undo !== undefined)
|
|
255
|
+
lines.push(record.undo);
|
|
256
|
+
return lines;
|
|
257
|
+
}
|
|
258
|
+
/** Strips the ids a user's eyes must not show (` id=save`) from text the SDK composed (error messages, `Closest:` lists). */
|
|
259
|
+
export function withoutIds(text) {
|
|
260
|
+
return text.replace(/ id=[^\s,)]*[^\s,).]/g, "");
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Strips what a field holds (` value="…"`, ` placeholder="…"`, a quoted string with its escapes, or a bare number or
|
|
264
|
+
* word) from a step's sentence: what was typed may be private, and the sentence goes into the report and the export.
|
|
265
|
+
*/
|
|
266
|
+
export function withoutFieldText(text) {
|
|
267
|
+
return text.replace(/ (?:value|placeholder)=(?:"(?:[^"\\]|\\.)*"(?:…\(\+\d+\))?|[^\s"]+)/g, "");
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* `scheme://…`, and also `scheme:/…` and `scheme:…` (an OAuth callback such as `com.example.app:/oauth2redirect?code=…`).
|
|
271
|
+
* The short forms count as links only when what follows has a `?`, `#` or `/`, so "10:30" and "Note: …" stay as they are.
|
|
272
|
+
*/
|
|
273
|
+
const URL_IN_TEXT = /\b[A-Za-z][A-Za-z0-9+.-]*:(?:\/\/)?[^\s"'<>]+/g;
|
|
274
|
+
/** A `scheme:/path?query#fragment` or `scheme:path?query` link: no authority; query, fragment and token-like segments go. */
|
|
275
|
+
function cutOpaque(bare, colon) {
|
|
276
|
+
const scheme = bare.slice(0, colon + 1);
|
|
277
|
+
let rest = bare.slice(colon + 1);
|
|
278
|
+
if (!/[?#/]/.test(rest))
|
|
279
|
+
return bare;
|
|
280
|
+
const hashAt = rest.indexOf("#");
|
|
281
|
+
const fragment = hashAt >= 0 ? "#…" : "";
|
|
282
|
+
if (hashAt >= 0)
|
|
283
|
+
rest = rest.slice(0, hashAt);
|
|
284
|
+
const queryAt = rest.indexOf("?");
|
|
285
|
+
const query = queryAt >= 0 ? "?…" : "";
|
|
286
|
+
if (queryAt >= 0)
|
|
287
|
+
rest = rest.slice(0, queryAt);
|
|
288
|
+
const path = rest
|
|
289
|
+
.split("/")
|
|
290
|
+
.map((segment) => (SECRET_SEGMENT.test(segment) ? "…" : segment))
|
|
291
|
+
.join("/");
|
|
292
|
+
return `${scheme}${path}${query}${fragment}`;
|
|
293
|
+
}
|
|
294
|
+
/** A path segment that looks like a token or an id worth hiding: 16 or more of letters, digits, - and _, with a digit. */
|
|
295
|
+
const SECRET_SEGMENT = /^(?=[A-Za-z0-9_-]*\d)[A-Za-z0-9_-]{16,}$/;
|
|
296
|
+
/**
|
|
297
|
+
* Cuts what a link may carry that isn't the place it leads (a sign-in token, a reset code, a session): the query and
|
|
298
|
+
* the fragment become `?…` and `#…`, a user and password before the host go, and a token-like path segment becomes
|
|
299
|
+
* `…`. The scheme, host and the rest of the path stay, so the report still says where the link went.
|
|
300
|
+
*/
|
|
301
|
+
export function withoutUrlSecrets(text) {
|
|
302
|
+
return text.replace(URL_IN_TEXT, (url) => {
|
|
303
|
+
// A drive path (`C:\…` or `C:/…`) is a file, not a link.
|
|
304
|
+
if (/^[A-Za-z]:[\\/]/.test(url))
|
|
305
|
+
return url;
|
|
306
|
+
const trail = /[.,;:!?)\]]+$/.exec(url)?.[0] ?? "";
|
|
307
|
+
const bare = trail === "" ? url : url.slice(0, -trail.length);
|
|
308
|
+
const colon = bare.indexOf(":");
|
|
309
|
+
if (!bare.startsWith("//", colon + 1))
|
|
310
|
+
return `${cutOpaque(bare, colon)}${trail}`;
|
|
311
|
+
const scheme = bare.slice(0, colon + 3);
|
|
312
|
+
let rest = bare.slice(scheme.length);
|
|
313
|
+
const hashAt = rest.indexOf("#");
|
|
314
|
+
const fragment = hashAt >= 0 ? "#…" : "";
|
|
315
|
+
if (hashAt >= 0)
|
|
316
|
+
rest = rest.slice(0, hashAt);
|
|
317
|
+
const queryAt = rest.indexOf("?");
|
|
318
|
+
const query = queryAt >= 0 ? "?…" : "";
|
|
319
|
+
if (queryAt >= 0)
|
|
320
|
+
rest = rest.slice(0, queryAt);
|
|
321
|
+
const slash = rest.indexOf("/");
|
|
322
|
+
let authority = slash >= 0 ? rest.slice(0, slash) : rest;
|
|
323
|
+
const path = slash >= 0 ? rest.slice(slash) : "";
|
|
324
|
+
const at = authority.lastIndexOf("@");
|
|
325
|
+
if (at >= 0)
|
|
326
|
+
authority = authority.slice(at + 1);
|
|
327
|
+
const cleanPath = path
|
|
328
|
+
.split("/")
|
|
329
|
+
.map((segment) => (SECRET_SEGMENT.test(segment) ? "…" : segment))
|
|
330
|
+
.join("/");
|
|
331
|
+
return `${scheme}${authority}${cleanPath}${query}${fragment}${trail}`;
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
/** The answer to `id` or `label` as a target in a journey (§17.1). */
|
|
335
|
+
export const IDS_HIDDEN = "Error bad_params: in a journey, ids and labels are hidden; use a ref or the visible text";
|
|
336
|
+
//# sourceMappingURL=journey.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"journey.js","sourceRoot":"","sources":["../src/journey.ts"],"names":[],"mappings":"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"}
|