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.
Files changed (49) hide show
  1. package/dist/audit.d.ts +2 -0
  2. package/dist/audit.js +1 -1
  3. package/dist/audit.js.map +1 -1
  4. package/dist/cli.js +4 -0
  5. package/dist/cli.js.map +1 -1
  6. package/dist/format.d.ts +4 -0
  7. package/dist/format.js +61 -20
  8. package/dist/format.js.map +1 -1
  9. package/dist/images.d.ts +27 -0
  10. package/dist/images.js +50 -0
  11. package/dist/images.js.map +1 -1
  12. package/dist/journey.d.ts +259 -0
  13. package/dist/journey.js +336 -0
  14. package/dist/journey.js.map +1 -0
  15. package/dist/journeyexport.d.ts +58 -0
  16. package/dist/journeyexport.js +318 -0
  17. package/dist/journeyexport.js.map +1 -0
  18. package/dist/journeygif.d.ts +62 -0
  19. package/dist/journeygif.js +192 -0
  20. package/dist/journeygif.js.map +1 -0
  21. package/dist/journeyreport.d.ts +202 -0
  22. package/dist/journeyreport.js +664 -0
  23. package/dist/journeyreport.js.map +1 -0
  24. package/dist/mcp.d.ts +1 -0
  25. package/dist/mcp.js +27 -1
  26. package/dist/mcp.js.map +1 -1
  27. package/dist/media.d.ts +86 -0
  28. package/dist/media.js +244 -0
  29. package/dist/media.js.map +1 -0
  30. package/dist/protocol.d.ts +4 -0
  31. package/dist/protocol.js +2 -0
  32. package/dist/protocol.js.map +1 -1
  33. package/dist/run.js +1 -1
  34. package/dist/run.js.map +1 -1
  35. package/dist/server.d.ts +2 -0
  36. package/dist/server.js +8 -0
  37. package/dist/server.js.map +1 -1
  38. package/dist/tool-text-data.d.ts +3 -0
  39. package/dist/tool-text-data.js +3 -0
  40. package/dist/tool-text-data.js.map +1 -1
  41. package/dist/tools.d.ts +213 -0
  42. package/dist/tools.js +1075 -28
  43. package/dist/tools.js.map +1 -1
  44. package/dist/uxcheck.d.ts +102 -0
  45. package/dist/uxcheck.js +128 -0
  46. package/dist/uxcheck.js.map +1 -0
  47. package/package.json +2 -1
  48. package/skills/tapline/SKILL.md +7 -0
  49. package/skills/tapline/references/personas.md +45 -0
package/dist/tools.d.ts CHANGED
@@ -2,8 +2,12 @@ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
2
2
  import { z } from "zod";
3
3
  import type { ControlQueue } from "./control.js";
4
4
  import type { InputOutcome, OverlayRead, PersonInput, QualityPreset, ViewerAction } from "./viewer.js";
5
+ import { Journey, type JourneyState } from "./journey.js";
6
+ import { type Runner } from "./journeyexport.js";
5
7
  import { Confirmations } from "./confirm.js";
6
8
  import { type PolicyFile } from "./policy.js";
9
+ import { type UxJourneyHook, type UxRules } from "./uxcheck.js";
10
+ import { MediaState } from "./media.js";
7
11
  import { type TaplineHost } from "./server.js";
8
12
  export declare const targetSchema: z.ZodObject<{
9
13
  ref: z.ZodOptional<z.ZodString>;
@@ -29,6 +33,7 @@ export declare const toolShapes: {
29
33
  readonly labels: z.ZodOptional<z.ZodBoolean>;
30
34
  };
31
35
  readonly check_layout: {};
36
+ readonly ux_check: {};
32
37
  readonly audit: {
33
38
  readonly types: z.ZodOptional<z.ZodArray<z.ZodEnum<{
34
39
  contrast: "contrast";
@@ -270,9 +275,89 @@ export declare const toolShapes: {
270
275
  readonly seconds: z.ZodNumber;
271
276
  readonly screenshot: z.ZodOptional<z.ZodBoolean>;
272
277
  };
278
+ readonly media: {
279
+ add: z.ZodOptional<z.ZodArray<z.ZodString>>;
280
+ confirm: z.ZodOptional<z.ZodBoolean>;
281
+ remove: z.ZodOptional<z.ZodBoolean>;
282
+ picker: z.ZodOptional<z.ZodBoolean>;
283
+ };
273
284
  readonly session_report: {
274
285
  readonly since: z.ZodOptional<z.ZodNumber>;
275
286
  };
287
+ readonly journey: {
288
+ readonly start: z.ZodOptional<z.ZodBoolean>;
289
+ readonly goal: z.ZodOptional<z.ZodString>;
290
+ readonly persona: z.ZodOptional<z.ZodString>;
291
+ readonly conditions: z.ZodOptional<z.ZodObject<{
292
+ language: z.ZodOptional<z.ZodString>;
293
+ region: z.ZodOptional<z.ZodString>;
294
+ text_size: z.ZodOptional<z.ZodEnum<{
295
+ s: "s";
296
+ m: "m";
297
+ xs: "xs";
298
+ l: "l";
299
+ xl: "xl";
300
+ xxl: "xxl";
301
+ xxxl: "xxxl";
302
+ ax1: "ax1";
303
+ ax2: "ax2";
304
+ ax3: "ax3";
305
+ ax4: "ax4";
306
+ ax5: "ax5";
307
+ system: "system";
308
+ }>>;
309
+ network: z.ZodOptional<z.ZodEnum<{
310
+ offline: "offline";
311
+ "3g": "3g";
312
+ lossy: "lossy";
313
+ }>>;
314
+ }, z.core.$strict>>;
315
+ readonly allow: z.ZodOptional<z.ZodArray<z.ZodString>>;
316
+ readonly eyes: z.ZodOptional<z.ZodEnum<{
317
+ agent: "agent";
318
+ user: "user";
319
+ }>>;
320
+ readonly stop: z.ZodOptional<z.ZodBoolean>;
321
+ readonly reached: z.ZodOptional<z.ZodBoolean>;
322
+ readonly why: z.ZodOptional<z.ZodString>;
323
+ readonly export: z.ZodOptional<z.ZodObject<{
324
+ to: z.ZodEnum<{
325
+ pr: "pr";
326
+ issue: "issue";
327
+ }>;
328
+ repo: z.ZodString;
329
+ pr: z.ZodOptional<z.ZodNumber>;
330
+ confirm: z.ZodOptional<z.ZodBoolean>;
331
+ public: z.ZodOptional<z.ZodBoolean>;
332
+ fork: z.ZodOptional<z.ZodBoolean>;
333
+ }, z.core.$strict>>;
334
+ readonly stress: z.ZodOptional<z.ZodObject<{
335
+ kind: z.ZodEnum<{
336
+ network: "network";
337
+ background: "background";
338
+ double_tap: "double_tap";
339
+ rotate: "rotate";
340
+ relaunch: "relaunch";
341
+ }>;
342
+ mode: z.ZodOptional<z.ZodEnum<{
343
+ offline: "offline";
344
+ "3g": "3g";
345
+ lossy: "lossy";
346
+ normal: "normal";
347
+ }>>;
348
+ target: z.ZodOptional<z.ZodObject<{
349
+ ref: z.ZodOptional<z.ZodString>;
350
+ text: z.ZodOptional<z.ZodString>;
351
+ x: z.ZodOptional<z.ZodNumber>;
352
+ y: z.ZodOptional<z.ZodNumber>;
353
+ }, z.core.$strict>>;
354
+ }, z.core.$strict>>;
355
+ readonly survives: z.ZodOptional<z.ZodObject<{
356
+ text: z.ZodOptional<z.ZodString>;
357
+ goal_step: z.ZodOptional<z.ZodString>;
358
+ }, z.core.$strict>>;
359
+ readonly done: z.ZodOptional<z.ZodBoolean>;
360
+ };
276
361
  readonly run: {
277
362
  readonly steps: z.ZodArray<z.ZodObject<{
278
363
  tool: z.ZodString;
@@ -323,6 +408,8 @@ export interface ToolsOptions {
323
408
  clientId?: () => string | undefined;
324
409
  /** The safety policy (AGENT-TOOLS 1.8 §11). Default: the built-in words; --no-policy passes empty lists. */
325
410
  policy?: PolicyFile;
411
+ /** The user's UX house rules (`--ux-rules FILE`, AGENT-TOOLS 1.12 §17.3). Default: none. */
412
+ uxRules?: UxRules;
326
413
  /** Where a person's OK is asked for and given (the live viewer listens). Default: a fresh one. */
327
414
  confirmations?: Confirmations;
328
415
  /** False when nobody can answer a request (--viewer off). Default true. */
@@ -375,6 +462,22 @@ export interface ToolsOptions {
375
462
  on: boolean;
376
463
  quality: QualityPreset;
377
464
  };
465
+ /** The clock a journey measures with, in ms (tests pass their own). Default: Date.now. */
466
+ clock?: () => number;
467
+ /**
468
+ * Called when a journey stops (AGENT-TOOLS 1.12 §17.5), with its state: the report writer's hook. The lines it
469
+ * returns follow the summary in the answer (`Findings: …`, `Report: <folder>`).
470
+ */
471
+ onJourneyStop?: (state: JourneyState) => string[] | Promise<string[]>;
472
+ /**
473
+ * Where journeys keep their report folders (e.g. ~/.tapline/journeys): each journey gets
474
+ * `<yyyy-mm-dd-hhmm>-<slug>/` with its frames, and `stop` writes the report there. Unset: no frames, no report.
475
+ */
476
+ journeysDir?: string;
477
+ /** Runs `gh` and `git` for `export` (AGENT-TOOLS 1.12 §17.5). Unset: export answers that it can't run. Tests pass a fake. */
478
+ exportRunner?: Runner;
479
+ /** Cap for the journey GIF in bytes (tests lower it; default 3 MB). */
480
+ gifMaxBytes?: number;
378
481
  }
379
482
  /**
380
483
  * The app's `feed` params. For measuring only, TAPLINE_FEED_GAP_MS (30–2000) replaces the app's
@@ -423,6 +526,12 @@ export declare class TaplineTools {
423
526
  private scrollBase;
424
527
  readonly confirmations: Confirmations;
425
528
  private readonly policy;
529
+ private readonly uxRules;
530
+ /**
531
+ * Hook for the journey (AGENT-TOOLS 1.12 §17): gives `ux_check` the action labels of earlier screens, and is told
532
+ * what each `ux_check` found. Null while no journey runs (naming is then not checked, and the answer says so).
533
+ */
534
+ uxJourney: UxJourneyHook | null;
426
535
  private readonly reloadSettleMs;
427
536
  private readonly stillGapMs;
428
537
  private readonly stillCapMs;
@@ -463,7 +572,62 @@ export declare class TaplineTools {
463
572
  private readonly crashBaseline;
464
573
  /** Set inside a tool call (and everything it awaits), so a call within a call (`run`'s steps) adds no notes. */
465
574
  private readonly noteScope;
575
+ /** The journey this agent has running (AGENT-TOOLS 1.12 §17.1); one at a time. */
576
+ private journeyRun;
577
+ /** The app the running journey started on (its identity and name): its clean-up goes to that app only. */
578
+ private journeyApp;
579
+ /** The journey's own app if it is connected (the current one first), else undefined: never another app (Codex review of 1.5.0). */
580
+ private journeySession;
581
+ /** Why a journey's clean-up didn't reach its app. */
582
+ private journeyAppGone;
583
+ /** The state of the journey that stopped last, for the report writer and the stress moments. */
584
+ private journeyDone;
585
+ /** Inside `run`: "run" for the batch's own checks (not counted), "step" for a step (counted like a call of its own). */
586
+ private readonly journeyScope;
587
+ /** The running journey's frames and report pictures (AGENT-TOOLS 1.12 §17.5); undefined without a `journeysDir`. */
588
+ private recorder;
589
+ /** The hook this journey gave `ux_check`, to take back at the stop. */
590
+ private journeyHook;
591
+ private pickerOff;
592
+ /** Where the last touch of the call in flight was, for the frame's tap ring. */
593
+ private lastTouch;
594
+ /** Stress moments that wait for a person (§17.4), by kind: what must survive. */
595
+ private readonly stressWaiting;
596
+ /** When the app last left the front or its link dropped, and when an app last connected (real time, for stress done). */
597
+ private readonly appLeftAt;
598
+ private readonly appConnectedAt;
599
+ /** Which app's picker event is being counted right now (set around the media state's own count). */
600
+ private pickerFrom;
601
+ /** "starting" until a journey's set-up is done, "stopping" until its clean-up is done: no other start meanwhile. */
602
+ private journeyBusy;
603
+ private readonly clock;
466
604
  constructor(host: TaplineHost, options: ToolsOptions);
605
+ /** The journey running now, for the stress moments and the report writer (AGENT-TOOLS 1.12 §17). */
606
+ currentJourney(): Journey | undefined;
607
+ /** The state of the journey that stopped last. */
608
+ finishedJourney(): JourneyState | undefined;
609
+ /** Whether the agent sees the app as a user does: a journey is running and its eyes are the user's. */
610
+ private userEyes;
611
+ /**
612
+ * Measures one call of a running journey and shows its answer as a user would see it. Calls inside `run` count
613
+ * as steps (the batch itself and its expectation checks do not); a dry run counts as nothing.
614
+ */
615
+ private journeyCall;
616
+ /** When a password field was last typed into, and whether that was within the second iOS still shows its last character. */
617
+ private secureTypedAt;
618
+ private secureWindow;
619
+ /** In a user's eyes no id reaches the agent, not even inside an error the app composed. */
620
+ private shownToUser;
621
+ /** `id` and `label` answer `bad_params` in a journey's user's eyes (§17.1). */
622
+ private hiddenTarget;
623
+ /** Whether the journey's `allow` lets this shortcut through (always, outside a user's eyes). */
624
+ private shortcutAllowed;
625
+ private shortcutWords;
626
+ /** A shortcut in a user's eyes: refused unless `allow` names it, and noted for the report when it goes through. */
627
+ private shortcutRefusal;
628
+ private static readonly SCROLL_TO_TARGET_OFF;
629
+ /** What a journey's user's eyes refuse in a step of `run`, before anything runs (a step number first); null when it is fine. */
630
+ private journeyStepRefusal;
467
631
  /** The agent's client id for the call log; the MCP server passes the client's name once it is known. */
468
632
  setClientId(read: () => string | undefined): void;
469
633
  /** A call refused before it reached its tool (an unknown argument): numbered and logged like any other, so the report counts it. */
@@ -526,6 +690,7 @@ export declare class TaplineTools {
526
690
  private dryRunBatch;
527
691
  /** One step of `run`, as its own tool call without a list. */
528
692
  private runStep;
693
+ private runStepNow;
529
694
  /** The screen's route names now (one cheap read), or null when the app has no router or didn't answer. */
530
695
  private currentRoute;
531
696
  /** Null when the expectation holds within its time; else how it failed. */
@@ -533,6 +698,12 @@ export declare class TaplineTools {
533
698
  private textExpectMissed;
534
699
  inspect(args: Shape<"inspect">): Promise<CallToolResult>;
535
700
  audit(args?: Shape<"audit">): Promise<CallToolResult>;
701
+ /** The house rule `max_taps_to_goal`, for the journey to check at stop; undefined when the user set none. */
702
+ get maxTapsToGoal(): number | undefined;
703
+ uxCheck(_args?: Shape<"ux_check">): Promise<CallToolResult>;
704
+ /** What `media` remembers per app: the asset ids it added, and the picker skips a journey report reads. */
705
+ readonly mediaState: MediaState;
706
+ media(args?: Shape<"media">): Promise<CallToolResult>;
536
707
  checkLayout(_args?: Shape<"check_layout">): Promise<CallToolResult>;
537
708
  /** Saves a file-mode screenshot (0600, newest `screenshotKeep` kept) and returns its path. */
538
709
  private saveShot;
@@ -542,6 +713,8 @@ export declare class TaplineTools {
542
713
  private takePersonNote;
543
714
  /** An action answered with no list and no changes: the call log can't say what is in the list any more. */
544
715
  private markListUnseen;
716
+ /** Remembers where a touch landed (points, and the touched element's frame) for the journey's frame and GIF. */
717
+ private noteTouch;
545
718
  /** Runs a request, then (unless disabled) appends the fresh element list and how long the app took to settle. */
546
719
  private act;
547
720
  /**
@@ -670,6 +843,8 @@ export declare class TaplineTools {
670
843
  scroll(args: Shape<"scroll">): Promise<CallToolResult>;
671
844
  toggle(args: Shape<"toggle">): Promise<CallToolResult>;
672
845
  appCommand(args: Shape<"app_command">): Promise<CallToolResult>;
846
+ /** AGENT-TOOLS 1.11 §16.4: a policy whose block list holds `network` refuses a condition; `normal` always goes. */
847
+ private networkRefusal;
673
848
  waitFor(args: Shape<"wait_for">): Promise<CallToolResult>;
674
849
  /** A drag through React Native's touch system (AGENT-TOOLS 5.2): what a pan view or a swipe-to-close sheet handles. */
675
850
  swipe(args: Shape<"swipe">): Promise<CallToolResult>;
@@ -687,6 +862,44 @@ export declare class TaplineTools {
687
862
  /** One measuring window in the app: start, (the tap,) wait out `seconds`, stop. */
688
863
  private measureWindow;
689
864
  performance(args?: Shape<"performance">): Promise<CallToolResult>;
865
+ journey(args?: Shape<"journey">): Promise<CallToolResult>;
866
+ private journeyStart;
867
+ private journeyStarted;
868
+ /** Opens the report folder for a journey that has somewhere to keep one, and hands `ux_check` the hook that feeds it. */
869
+ private startRecorder;
870
+ /** The recorder's eyes: a read that touches nothing, and a small picture. */
871
+ private frameSource;
872
+ private journeyStop;
873
+ private journeyStopped;
874
+ /** `export` of `stop`: the report to GitHub through the user's own gh and git; the report stays local when it fails. */
875
+ private exportReport;
876
+ private journeyStress;
877
+ private waitForPerson;
878
+ /** The screen's size in points from a read that touches nothing; null when the app doesn't answer. */
879
+ private freshScreenSize;
880
+ /**
881
+ * Why a person's stress moment can't be taken as done, or null when the app shows it happened: background left the
882
+ * front (or the link dropped) since it was asked; relaunch connected anew; rotate flipped the screen's size.
883
+ */
884
+ private stressUnseen;
885
+ /** Waits for an app after a reload or a person leaving it (a new session comes up), a few seconds at most. */
886
+ private reconnected;
887
+ private stressNetwork;
888
+ /** The same touch twice, 80 ms apart, each through the usual checks and the policy. */
889
+ private stressDoubleTap;
890
+ /** Records the moment and answers it: `Stress: <kind>; it survived: …` or `…; it didn't survive: …`. */
891
+ private stressDone;
892
+ /** Whether what had to survive is still there, from a read that touches nothing. */
893
+ private survivalOf;
894
+ /** `goal_step`: a step number (the screen that step ended on) or a screen's name (part of its route). */
895
+ private goalStepHolds;
896
+ /** The command and arguments that set one of a journey's conditions. */
897
+ private conditionCall;
898
+ /** Runs one condition command straight on the app (a journey's own, not the agent's shortcut); the app's answer may say what it was before. */
899
+ private runCondition;
900
+ private applyCondition;
901
+ /** At the stop: network goes back to normal, text size to the phone's own, language and region to what the app said they were. */
902
+ private undoConditions;
690
903
  wait(args: Shape<"wait">): Promise<CallToolResult>;
691
904
  }
692
905
  export {};