tapline-host 1.5.0 → 1.6.1

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 (110) hide show
  1. package/dist/accounts.d.ts +72 -0
  2. package/dist/accounts.js +208 -0
  3. package/dist/accounts.js.map +1 -0
  4. package/dist/actionlog.d.ts +20 -0
  5. package/dist/actionlog.js.map +1 -1
  6. package/dist/animations.d.ts +39 -0
  7. package/dist/animations.js +124 -0
  8. package/dist/animations.js.map +1 -0
  9. package/dist/api.d.ts +43 -0
  10. package/dist/api.js +154 -0
  11. package/dist/api.js.map +1 -0
  12. package/dist/audit.d.ts +1 -0
  13. package/dist/bin.d.ts +2 -0
  14. package/dist/bin.js +19 -0
  15. package/dist/bin.js.map +1 -0
  16. package/dist/brief.d.ts +41 -0
  17. package/dist/brief.js +78 -0
  18. package/dist/brief.js.map +1 -0
  19. package/dist/cli.d.ts +41 -1
  20. package/dist/cli.js +97 -54
  21. package/dist/cli.js.map +1 -1
  22. package/dist/conditions.d.ts +36 -0
  23. package/dist/conditions.js +67 -0
  24. package/dist/conditions.js.map +1 -0
  25. package/dist/confirm.d.ts +21 -2
  26. package/dist/confirm.js +39 -6
  27. package/dist/confirm.js.map +1 -1
  28. package/dist/dispatch.d.ts +27 -0
  29. package/dist/dispatch.js +114 -0
  30. package/dist/dispatch.js.map +1 -0
  31. package/dist/doctor.d.ts +5 -0
  32. package/dist/doctor.js +20 -0
  33. package/dist/doctor.js.map +1 -1
  34. package/dist/drive.d.ts +184 -0
  35. package/dist/drive.js +908 -0
  36. package/dist/drive.js.map +1 -0
  37. package/dist/elicit.d.ts +90 -0
  38. package/dist/elicit.js +179 -0
  39. package/dist/elicit.js.map +1 -0
  40. package/dist/format.d.ts +12 -0
  41. package/dist/format.js +20 -4
  42. package/dist/format.js.map +1 -1
  43. package/dist/images.d.ts +8 -0
  44. package/dist/images.js +26 -6
  45. package/dist/images.js.map +1 -1
  46. package/dist/inspect.d.ts +1 -0
  47. package/dist/journey.d.ts +18 -1
  48. package/dist/journey.js +32 -0
  49. package/dist/journey.js.map +1 -1
  50. package/dist/journeyreport.js +4 -2
  51. package/dist/journeyreport.js.map +1 -1
  52. package/dist/mapcmd.d.ts +200 -0
  53. package/dist/mapcmd.js +412 -0
  54. package/dist/mapcmd.js.map +1 -0
  55. package/dist/mapfile.d.ts +155 -0
  56. package/dist/mapfile.js +575 -0
  57. package/dist/mapfile.js.map +1 -0
  58. package/dist/mcp.d.ts +14 -12
  59. package/dist/mcp.js +50 -344
  60. package/dist/mcp.js.map +1 -1
  61. package/dist/media.d.ts +2 -0
  62. package/dist/media.js +21 -2
  63. package/dist/media.js.map +1 -1
  64. package/dist/nochange.d.ts +77 -0
  65. package/dist/nochange.js +77 -0
  66. package/dist/nochange.js.map +1 -0
  67. package/dist/places.d.ts +239 -0
  68. package/dist/places.js +823 -0
  69. package/dist/places.js.map +1 -0
  70. package/dist/policy.d.ts +18 -0
  71. package/dist/policy.js +52 -0
  72. package/dist/policy.js.map +1 -1
  73. package/dist/protocol.d.ts +23 -1
  74. package/dist/protocol.js +23 -0
  75. package/dist/protocol.js.map +1 -1
  76. package/dist/reflexes.d.ts +59 -0
  77. package/dist/reflexes.js +133 -0
  78. package/dist/reflexes.js.map +1 -0
  79. package/dist/report.d.ts +32 -2
  80. package/dist/report.js +154 -9
  81. package/dist/report.js.map +1 -1
  82. package/dist/routes.d.ts +115 -0
  83. package/dist/routes.js +287 -0
  84. package/dist/routes.js.map +1 -0
  85. package/dist/run.d.ts +28 -1
  86. package/dist/run.js +32 -3
  87. package/dist/run.js.map +1 -1
  88. package/dist/runtime.d.ts +60 -0
  89. package/dist/runtime.js +255 -0
  90. package/dist/runtime.js.map +1 -0
  91. package/dist/script.d.ts +114 -10
  92. package/dist/script.js +30 -2
  93. package/dist/script.js.map +1 -1
  94. package/dist/server.d.ts +46 -2
  95. package/dist/server.js +80 -13
  96. package/dist/server.js.map +1 -1
  97. package/dist/thincall.d.ts +13 -0
  98. package/dist/thincall.js +335 -0
  99. package/dist/thincall.js.map +1 -0
  100. package/dist/tool-text-data.d.ts +7 -5
  101. package/dist/tool-text-data.js +8 -6
  102. package/dist/tool-text-data.js.map +1 -1
  103. package/dist/tool-text.d.ts +1 -1
  104. package/dist/tools.d.ts +373 -6
  105. package/dist/tools.js +1889 -195
  106. package/dist/tools.js.map +1 -1
  107. package/dist/uxcheck.d.ts +1 -0
  108. package/package.json +2 -2
  109. package/skills/tapline/SKILL.md +50 -11
  110. package/skills/tapline/references/setup.md +6 -1
@@ -0,0 +1,72 @@
1
+ import { z } from "zod";
2
+ export declare const accountsFileSchema: z.ZodObject<{
3
+ version: z.ZodLiteral<1>;
4
+ accounts: z.ZodRecord<z.ZodString, z.ZodObject<{
5
+ username: z.ZodOptional<z.ZodString>;
6
+ password: z.ZodOptional<z.ZodString>;
7
+ passcode: z.ZodOptional<z.ZodString>;
8
+ apps: z.ZodOptional<z.ZodArray<z.ZodString>>;
9
+ }, z.core.$strip>>;
10
+ }, z.core.$strip>;
11
+ export type AccountsFile = z.infer<typeof accountsFileSchema>;
12
+ export type AccountField = "username" | "password";
13
+ export type AccountResolved = {
14
+ ok: true;
15
+ value: string;
16
+ } | {
17
+ ok: false;
18
+ code: "not_found" | "bad_params";
19
+ message: string;
20
+ };
21
+ export interface AccountStore {
22
+ /** The accounts' names, never their values. */
23
+ names(): string[];
24
+ /** One value of an account, for an app. */
25
+ resolve(name: string, field: AccountField, appId: string): AccountResolved;
26
+ /** Replaces every username with `<tester2's username>` and every password with `<tester2's password>`. */
27
+ redact(text: string): string;
28
+ }
29
+ /** What the accounts file gave: its accounts, or why none were loaded (the git message). */
30
+ export type AccountsLoad = {
31
+ store: AccountStore;
32
+ } | {
33
+ store: null;
34
+ blocked: string;
35
+ };
36
+ export interface GitProbe {
37
+ /** Whether the folder is inside a git work tree. */
38
+ insideWorkTree(dir: string): Promise<boolean>;
39
+ /** Whether git ignores the file (a tracked file counts as not ignored). */
40
+ ignored(file: string): Promise<boolean>;
41
+ }
42
+ /** The real probe: the user's own git, run without a shell. When git can't run, a `.git` above the file counts as a work tree. */
43
+ export declare const realGitProbe: GitProbe;
44
+ /** What the user is told wherever the accounts option is described (the parameter text, `--help`, `doctor`). */
45
+ export declare const ACCOUNTS_WARNING = "A password stays out of pictures only while its field is secure; a \"show password\" toggle shows it. Keep the accounts file outside the folders the agent may read.";
46
+ /** The refusal's words, for the first answer, `doctor` and every use. */
47
+ export declare function blockedMessage(file: string): string;
48
+ export declare function accountStore(file: AccountsFile): AccountStore;
49
+ /**
50
+ * Reads the accounts file. Inside a git work tree that doesn't ignore it, nothing is read or loaded. A file that can't
51
+ * be read or isn't the format throws a plain message that never quotes the file (it holds secrets).
52
+ */
53
+ export declare function loadAccounts(file: string, probe?: GitProbe): Promise<AccountsLoad>;
54
+ /**
55
+ * Scrubs every string in a JSON value (an app's answer), keeping its shape. Property names are scrubbed too; two names
56
+ * that come out the same stay apart with a numbered suffix.
57
+ */
58
+ export declare function redactValue(value: unknown, redact: (text: string) => string): unknown;
59
+ export type AccountText = {
60
+ ok: true;
61
+ text: string;
62
+ field: AccountField | null;
63
+ } | {
64
+ ok: false;
65
+ code: "not_found" | "bad_params";
66
+ message: string;
67
+ };
68
+ /**
69
+ * `${account.username}` or `${account.password}` becomes the value, but only when it is the whole text: joined with
70
+ * other text it could get a password past the secure-field rule. Text without a placeholder passes unchanged (field null).
71
+ */
72
+ export declare function substituteAccount(text: string, store: AccountStore, name: string | undefined, appId: string): AccountText;
@@ -0,0 +1,208 @@
1
+ import { execFile } from "node:child_process";
2
+ import { existsSync, readFileSync, realpathSync } from "node:fs";
3
+ import { dirname, join, parse, resolve } from "node:path";
4
+ import { z } from "zod";
5
+ /**
6
+ * Test accounts (AGENT-TOOLS 1.13 §18.6). The file holds real test credentials, so this module is built to keep them
7
+ * from the agent: the file is refused inside a git work tree that doesn't ignore it, a value is typed only as the
8
+ * whole text of a step, and `redact` scrubs every value from what the app sends back.
9
+ */
10
+ const ACCOUNT_NAME = /^[\w.-]{1,60}$/;
11
+ // A shorter value would be scrubbed out of unrelated text. The message quotes no value.
12
+ const SHORT = "must be at least 3 characters, so scrubbing it can't garble other text";
13
+ const accountSchema = z.object({
14
+ username: z.string().min(3, SHORT).optional(),
15
+ password: z.string().min(3, SHORT).optional(),
16
+ /** Tapwright's: the phone's passcode. Tapline loads it without complaint and never types it. */
17
+ passcode: z.string().min(1).optional(),
18
+ apps: z.array(z.string().min(1)).optional(),
19
+ });
20
+ export const accountsFileSchema = z.object({
21
+ version: z.literal(1),
22
+ accounts: z.record(z.string().regex(ACCOUNT_NAME, "account names use letters, digits, '.', '_' and '-'"), accountSchema),
23
+ });
24
+ function git(args, cwd) {
25
+ return new Promise((done) => {
26
+ execFile("git", args, { cwd, timeout: 10_000, windowsHide: true, encoding: "utf8" }, (error, stdout) => {
27
+ if (error === null)
28
+ return done({ code: 0, stdout });
29
+ const code = error.code;
30
+ done({ code: typeof code === "number" ? code : null, stdout: "" });
31
+ });
32
+ });
33
+ }
34
+ /** Whether a folder or one above it holds a `.git`: the answer when git itself can't be run. */
35
+ function hasGitAbove(dir) {
36
+ let at = resolve(dir);
37
+ for (;;) {
38
+ if (existsSync(join(at, ".git")))
39
+ return true;
40
+ const up = dirname(at);
41
+ if (up === at || parse(at).root === at)
42
+ return false;
43
+ at = up;
44
+ }
45
+ }
46
+ /** The real probe: the user's own git, run without a shell. When git can't run, a `.git` above the file counts as a work tree. */
47
+ export const realGitProbe = {
48
+ async insideWorkTree(dir) {
49
+ const out = await git(["rev-parse", "--is-inside-work-tree"], dir);
50
+ return out.code === 0 ? out.stdout.trim() === "true" : hasGitAbove(dir);
51
+ },
52
+ async ignored(file) {
53
+ return (await git(["check-ignore", "-q", "--", file], dirname(file))).code === 0;
54
+ },
55
+ };
56
+ /** What the user is told wherever the accounts option is described (the parameter text, `--help`, `doctor`). */
57
+ export const ACCOUNTS_WARNING = "A password stays out of pictures only while its field is secure; a \"show password\" toggle shows it. Keep the accounts file outside the folders the agent may read.";
58
+ /** The refusal's words, for the first answer, `doctor` and every use. */
59
+ export function blockedMessage(file) {
60
+ return `accounts file is inside the git repo at ${file} and not ignored; move it or add it to .gitignore.`;
61
+ }
62
+ /** The invisible direction marks the app strips from text (react-native-tapline's `displayText`). */
63
+ const DIRECTION_MARKS = /[‎‏‪-‮⁦-⁩]/g;
64
+ /**
65
+ * The shapes a value can take on its way back: as it is, inside a JSON string, in a URL (percent or form encoded), and
66
+ * as the app's `normalizeText` leaves it (direction marks gone, whitespace collapsed and trimmed).
67
+ */
68
+ function variantsOf(value) {
69
+ const normalized = value.replace(DIRECTION_MARKS, "").replace(/\s+/g, " ").trim();
70
+ const forms = new Set();
71
+ for (const base of [value, normalized]) {
72
+ forms.add(base);
73
+ forms.add(JSON.stringify(base).slice(1, -1));
74
+ const percent = encodeURIComponent(base);
75
+ forms.add(percent);
76
+ forms.add(percent.replace(/%20/g, "+"));
77
+ // URLSearchParams encodes more than encodeURIComponent does (`~` becomes %7E).
78
+ forms.add(new URLSearchParams({ k: base }).toString().slice(2));
79
+ }
80
+ return [...forms].filter((form) => form !== "");
81
+ }
82
+ /** Longest variants first, so a value that holds another is scrubbed whole. */
83
+ function scrubber(accounts) {
84
+ const pairs = [];
85
+ for (const [name, account] of Object.entries(accounts)) {
86
+ if (account.username !== undefined)
87
+ for (const form of variantsOf(account.username))
88
+ pairs.push([form, `<${name}'s username>`]);
89
+ if (account.password !== undefined)
90
+ for (const form of variantsOf(account.password))
91
+ pairs.push([form, `<${name}'s password>`]);
92
+ }
93
+ pairs.sort((a, b) => b[0].length - a[0].length);
94
+ return (text) => {
95
+ let out = text;
96
+ for (const [value, token] of pairs)
97
+ if (out.includes(value))
98
+ out = out.split(value).join(token);
99
+ return out;
100
+ };
101
+ }
102
+ export function accountStore(file) {
103
+ const accounts = file.accounts;
104
+ const scrub = scrubber(accounts);
105
+ const names = Object.keys(accounts);
106
+ const list = () => (names.length === 0 ? "the accounts file has none" : `the accounts are ${names.join(", ")}`);
107
+ return {
108
+ names: () => [...names],
109
+ redact: scrub,
110
+ resolve(name, field, appId) {
111
+ const account = Object.prototype.hasOwnProperty.call(accounts, name) ? accounts[name] : undefined;
112
+ if (account === undefined)
113
+ return { ok: false, code: "not_found", message: `no account "${name}"; ${list()}.` };
114
+ if (account.apps !== undefined && !account.apps.includes(appId)) {
115
+ return { ok: false, code: "bad_params", message: `account "${name}" isn't for this app (${appId}); it is for ${account.apps.join(", ")}.` };
116
+ }
117
+ const value = account[field];
118
+ if (value === undefined)
119
+ return { ok: false, code: "bad_params", message: `account "${name}" has no ${field}.` };
120
+ return { ok: true, value };
121
+ },
122
+ };
123
+ }
124
+ /**
125
+ * Reads the accounts file. Inside a git work tree that doesn't ignore it, nothing is read or loaded. A file that can't
126
+ * be read or isn't the format throws a plain message that never quotes the file (it holds secrets).
127
+ */
128
+ export async function loadAccounts(file, probe = realGitProbe) {
129
+ const path = resolve(file);
130
+ if (!existsSync(path))
131
+ throw new Error(`the accounts file ${path} doesn't exist`);
132
+ // Through a symlink or a junction the file may really sit in a repo: ask about where it is.
133
+ let real = path;
134
+ try {
135
+ real = realpathSync(path);
136
+ }
137
+ catch {
138
+ // the path stands
139
+ }
140
+ // A `.git` folder in the path is a repo's own files, which no .gitignore covers.
141
+ const inGitDir = real.split(/[\\/]/).includes(".git");
142
+ if (inGitDir || ((await probe.insideWorkTree(dirname(real))) && !(await probe.ignored(real)))) {
143
+ return { store: null, blocked: blockedMessage(path) };
144
+ }
145
+ let json;
146
+ try {
147
+ json = JSON.parse(readFileSync(real, "utf8"));
148
+ }
149
+ catch {
150
+ // Node's own message quotes part of the text, and this file holds passwords.
151
+ throw new Error(`the accounts file ${path} isn't valid JSON`);
152
+ }
153
+ const parsed = accountsFileSchema.safeParse(json);
154
+ if (!parsed.success) {
155
+ const why = parsed.error.issues.map((issue) => `${issue.path.join(".") || "file"}: ${issue.message}`).join("; ");
156
+ throw new Error(`the accounts file ${path} isn't the right format: ${why}`);
157
+ }
158
+ return { store: accountStore(parsed.data) };
159
+ }
160
+ /**
161
+ * Scrubs every string in a JSON value (an app's answer), keeping its shape. Property names are scrubbed too; two names
162
+ * that come out the same stay apart with a numbered suffix.
163
+ */
164
+ export function redactValue(value, redact) {
165
+ if (typeof value === "string")
166
+ return redact(value);
167
+ if (Array.isArray(value))
168
+ return value.map((item) => redactValue(item, redact));
169
+ if (typeof value === "object" && value !== null) {
170
+ const out = {};
171
+ for (const [key, item] of Object.entries(value)) {
172
+ const base = redact(key);
173
+ let name = base;
174
+ for (let n = 2; Object.prototype.hasOwnProperty.call(out, name); n++)
175
+ name = `${base} #${n}`;
176
+ // defineProperty keeps a name like "__proto__" an ordinary key.
177
+ Object.defineProperty(out, name, { value: redactValue(item, redact), enumerable: true, writable: true, configurable: true });
178
+ }
179
+ return out;
180
+ }
181
+ return value;
182
+ }
183
+ const WHOLE = /^\$\{account\.(\w+)\}$/;
184
+ /**
185
+ * `${account.username}` or `${account.password}` becomes the value, but only when it is the whole text: joined with
186
+ * other text it could get a password past the secure-field rule. Text without a placeholder passes unchanged (field null).
187
+ */
188
+ export function substituteAccount(text, store, name, appId) {
189
+ const whole = WHOLE.exec(text);
190
+ if (whole === null) {
191
+ if (text.includes("${account."))
192
+ return { ok: false, code: "bad_params", message: "an account value is the whole text of a step, not part of one." };
193
+ return { ok: true, text, field: null };
194
+ }
195
+ const field = whole[1];
196
+ if (field === "passcode") {
197
+ return { ok: false, code: "bad_params", message: "an account's passcode is typed only by Tapwright on a locked phone's keypad; Tapline never types it." };
198
+ }
199
+ if (field !== "username" && field !== "password") {
200
+ return { ok: false, code: "bad_params", message: `\${account.${field ?? ""}} isn't a value an account has; use \${account.username} or \${account.password}.` };
201
+ }
202
+ if (name === undefined) {
203
+ return { ok: false, code: "bad_params", message: `name the account: add "account": "<name>" (${store.names().length === 0 ? "the accounts file has none" : `the accounts are ${store.names().join(", ")}`}).` };
204
+ }
205
+ const resolved = store.resolve(name, field, appId);
206
+ return resolved.ok ? { ok: true, text: resolved.value, field } : resolved;
207
+ }
208
+ //# sourceMappingURL=accounts.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"accounts.js","sourceRoot":"","sources":["../src/accounts.ts"],"names":[],"mappings":"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"}
@@ -14,7 +14,14 @@ export interface ActionLogEntry {
14
14
  ok: boolean;
15
15
  code?: string;
16
16
  reason?: string;
17
+ /** The time in the tool, in ms: an action's own, a read's whole call (AGENT-TOOLS 1.13 §16.1). `t` is when it began. */
17
18
  ms?: number;
19
+ /** 2: `t` is when the call began and `ms` its time. Older entries stamped the end, so the Time line leaves them out. */
20
+ v?: 2;
21
+ /** `"call"` when the call came through the thin call, a new process each time (§18.10). */
22
+ via?: "call";
23
+ /** `"fast"` when fast-forwarded animations were on while the call ran (PLAN-1.6 F4); the report says how many calls. */
24
+ animations?: "fast";
18
25
  app?: string;
19
26
  batch?: {
20
27
  id: string;
@@ -22,6 +29,8 @@ export interface ActionLogEntry {
22
29
  };
23
30
  dry_run?: boolean;
24
31
  confirmed?: boolean;
32
+ /** Where a person's OK came from: the host's dialog or the live view (AGENT-TOOLS 1.13 §11.3). */
33
+ confirmed_by?: "chat" | "live view";
25
34
  /** For typing: how many characters, never the text. */
26
35
  chars?: number;
27
36
  /** AGENT-TOOLS 1.11 §16.1: `"read"` for a call that isn't an action (look, wait_for, logs, ...). */
@@ -51,6 +60,17 @@ export interface ActionLogEntry {
51
60
  * Set on the call's action entries, so a report counts the call as failed (Codex review of 1.4.0).
52
61
  */
53
62
  call_failed?: string;
63
+ /** A `compare_screen` that matched under its threshold but named changed clusters (AGENT-TOOLS 1.13.1 item 2). */
64
+ matched_with_changes?: boolean;
65
+ /**
66
+ * A touch that took the app from one place to another: their names (the map's own, never screen text), and whether the map
67
+ * already held a proven road between them. The report uses it to say a way was known (AGENT-TOOLS 1.13 16.1).
68
+ */
69
+ way?: {
70
+ from: string;
71
+ to: string;
72
+ known: boolean;
73
+ };
54
74
  }
55
75
  export declare const LOG_KEEP_DAYS = 14;
56
76
  export declare class ActionLog {
@@ -1 +1 @@
1
- {"version":3,"file":"actionlog.js","sourceRoot":"","sources":["../src/actionlog.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"actionlog.js","sourceRoot":"","sources":["../src/actionlog.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,39 @@
1
+ import type { TaplineHost } from "./server.js";
2
+ /**
3
+ * Fast-forwarded animations on the host side (PLAN-1.6 F4, AGENT-TOOLS 1.13 18.12). The app does the work (its
4
+ * `animations` command and its three layers); the host remembers which sessions it switched on, so that it can
5
+ * put them back for a measurement and when the session ends. State is kept per host, not per tools object, because
6
+ * several agents' tools share one app.
7
+ */
8
+ /** The line every answer carries while fast animations are on (the shape of the network line). */
9
+ export declare const ANIMATIONS_LINE = "Animations: fast (Tapline).";
10
+ /** What a call says when it could not be run with animations normal. */
11
+ export declare const ANIMATIONS_NOT_PAUSED_NOTE = "Note: animations could not be set to normal for this call; it ran with fast animations.";
12
+ /** What a call that ran with animations paused says at its end. */
13
+ export declare const ANIMATIONS_PAUSED_NOTE = "Note: animations were normal during this call.";
14
+ /** Whether the host switched fast animations on for this session and they are meant to be on. */
15
+ export declare function animationsOn(host: TaplineHost, sessionId: string): boolean;
16
+ /** Records what the app's `animations` command was last set to. */
17
+ export declare function noteAnimations(host: TaplineHost, sessionId: string, speed: "fast" | "normal"): void;
18
+ /** Waits while a measurement holds the session at normal: an explicit switch to fast must not land inside it. */
19
+ export declare function afterPause(host: TaplineHost, sessionId: string): Promise<void>;
20
+ /**
21
+ * Runs `run` with animations normal when they are on for the session, and puts them back after, whatever `run` does.
22
+ * `paused` is true when they were on and are normal for this call; `failed` when the switch to normal did not go through
23
+ * (the call then ran fast, and says so). Pauses overlapping in one session are counted: normal is sent by the first and
24
+ * fast comes back when the last one ends.
25
+ */
26
+ export declare function withNormalAnimations<T>(host: TaplineHost, sessionId: string | undefined, run: () => Promise<T>): Promise<{
27
+ value: T;
28
+ paused: boolean;
29
+ failed: boolean;
30
+ }>;
31
+ /**
32
+ * Puts one session back to normal for good (a journey in a user's eyes starts). False when they were not on, or when
33
+ * the app refused the switch: the session then stays tracked as fast, so nothing reports animations as normal.
34
+ */
35
+ export declare function endAnimations(host: TaplineHost, sessionId: string): Promise<boolean>;
36
+ /** The session ends: every session this host switched to fast goes back to normal. A session that is gone is skipped. */
37
+ export declare function restoreAnimations(host: TaplineHost): Promise<void>;
38
+ /** Forgets a session that ended (the app restores itself on a disconnect). */
39
+ export declare function forgetAnimations(host: TaplineHost, sessionId: string): void;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Fast-forwarded animations on the host side (PLAN-1.6 F4, AGENT-TOOLS 1.13 18.12). The app does the work (its
3
+ * `animations` command and its three layers); the host remembers which sessions it switched on, so that it can
4
+ * put them back for a measurement and when the session ends. State is kept per host, not per tools object, because
5
+ * several agents' tools share one app.
6
+ */
7
+ /** The line every answer carries while fast animations are on (the shape of the network line). */
8
+ export const ANIMATIONS_LINE = "Animations: fast (Tapline).";
9
+ /** What a call says when it could not be run with animations normal. */
10
+ export const ANIMATIONS_NOT_PAUSED_NOTE = "Note: animations could not be set to normal for this call; it ran with fast animations.";
11
+ /** What a call that ran with animations paused says at its end. */
12
+ export const ANIMATIONS_PAUSED_NOTE = "Note: animations were normal during this call.";
13
+ const on = new WeakMap();
14
+ const pauses = new WeakMap();
15
+ function pausesOf(host) {
16
+ const known = pauses.get(host);
17
+ if (known !== undefined)
18
+ return known;
19
+ const made = new Map();
20
+ pauses.set(host, made);
21
+ return made;
22
+ }
23
+ function setOf(map, host) {
24
+ const known = map.get(host);
25
+ if (known !== undefined)
26
+ return known;
27
+ const made = new Set();
28
+ map.set(host, made);
29
+ return made;
30
+ }
31
+ /** Whether the host switched fast animations on for this session and they are meant to be on. */
32
+ export function animationsOn(host, sessionId) {
33
+ return setOf(on, host).has(sessionId);
34
+ }
35
+ /** Records what the app's `animations` command was last set to. */
36
+ export function noteAnimations(host, sessionId, speed) {
37
+ const sessions = setOf(on, host);
38
+ if (speed === "fast")
39
+ sessions.add(sessionId);
40
+ else
41
+ sessions.delete(sessionId);
42
+ }
43
+ /** Waits while a measurement holds the session at normal: an explicit switch to fast must not land inside it. */
44
+ export async function afterPause(host, sessionId) {
45
+ for (let pause = pausesOf(host).get(sessionId); pause !== undefined; pause = pausesOf(host).get(sessionId))
46
+ await pause.over;
47
+ }
48
+ async function send(host, sessionId, speed) {
49
+ try {
50
+ await host.request("command", { name: "animations", args: { speed } }, { sessionId });
51
+ return true;
52
+ }
53
+ catch {
54
+ return false;
55
+ }
56
+ }
57
+ /**
58
+ * Runs `run` with animations normal when they are on for the session, and puts them back after, whatever `run` does.
59
+ * `paused` is true when they were on and are normal for this call; `failed` when the switch to normal did not go through
60
+ * (the call then ran fast, and says so). Pauses overlapping in one session are counted: normal is sent by the first and
61
+ * fast comes back when the last one ends.
62
+ */
63
+ export async function withNormalAnimations(host, sessionId, run) {
64
+ if (sessionId === undefined || !animationsOn(host, sessionId))
65
+ return { value: await run(), paused: false, failed: false };
66
+ const all = pausesOf(host);
67
+ let pause = all.get(sessionId);
68
+ if (pause === undefined) {
69
+ let end = () => undefined;
70
+ const over = new Promise((resolve) => (end = resolve));
71
+ pause = { count: 0, ready: send(host, sessionId, "normal"), over, end };
72
+ all.set(sessionId, pause);
73
+ }
74
+ pause.count += 1;
75
+ const mine = pause;
76
+ const accepted = await mine.ready;
77
+ try {
78
+ return { value: await run(), paused: accepted, failed: !accepted };
79
+ }
80
+ finally {
81
+ mine.count -= 1;
82
+ if (mine.count === 0) {
83
+ if (all.get(sessionId) === mine)
84
+ all.delete(sessionId);
85
+ // A switch made during the call wins: only put fast back when it is still meant to be on.
86
+ try {
87
+ if (animationsOn(host, sessionId))
88
+ await send(host, sessionId, "fast");
89
+ }
90
+ finally {
91
+ mine.end();
92
+ }
93
+ }
94
+ }
95
+ }
96
+ /**
97
+ * Puts one session back to normal for good (a journey in a user's eyes starts). False when they were not on, or when
98
+ * the app refused the switch: the session then stays tracked as fast, so nothing reports animations as normal.
99
+ */
100
+ export async function endAnimations(host, sessionId) {
101
+ const sessions = setOf(on, host);
102
+ if (!sessions.has(sessionId))
103
+ return false;
104
+ if (!(await send(host, sessionId, "normal")))
105
+ return false;
106
+ sessions.delete(sessionId);
107
+ return true;
108
+ }
109
+ /** The session ends: every session this host switched to fast goes back to normal. A session that is gone is skipped. */
110
+ export async function restoreAnimations(host) {
111
+ const sessions = setOf(on, host);
112
+ const ids = [...sessions];
113
+ // A session the app would not put back stays tracked as fast.
114
+ await Promise.all(ids.map(async (id) => {
115
+ if (await send(host, id, "normal"))
116
+ sessions.delete(id);
117
+ }));
118
+ }
119
+ /** Forgets a session that ended (the app restores itself on a disconnect). */
120
+ export function forgetAnimations(host, sessionId) {
121
+ setOf(on, host).delete(sessionId);
122
+ pausesOf(host).delete(sessionId);
123
+ }
124
+ //# sourceMappingURL=animations.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"animations.js","sourceRoot":"","sources":["../src/animations.ts"],"names":[],"mappings":"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"}
package/dist/api.d.ts ADDED
@@ -0,0 +1,43 @@
1
+ import type { IncomingMessage, ServerResponse } from "node:http";
2
+ import type { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
3
+ /**
4
+ * `POST /api/<tool>` (AGENT-TOOLS 1.13 §18.10): the thin call's way in. Only a standalone `tapline host` sets an
5
+ * `api` handler; a host inside an agent's MCP server has none and answers 404, so one agent's session can't be
6
+ * driven by another's thin calls. The handler returns undefined for a tool that doesn't exist.
7
+ */
8
+ export type ApiHandler = (tool: string, args: Record<string, unknown>, clientId: string | undefined,
9
+ /** Aborts when the client disconnects before the answer: queued work that nobody waits for is skipped. */
10
+ signal: AbortSignal) => Promise<CallToolResult | undefined>;
11
+ /** The most a call's JSON may be. */
12
+ export declare const MAX_API_BODY: number;
13
+ export declare function safeEqual(a: string, b: string): boolean;
14
+ /** An address as one spelling: no brackets, lower case, and an IPv4-mapped IPv6 address as plain IPv4. */
15
+ export declare function normalizeAddress(address: string): string;
16
+ /**
17
+ * The host's proof that it holds the token: an HMAC of the caller's fresh challenge and of the address and port the request
18
+ * arrived on, keyed by the token. They are in it so that a listener on another port, or on another address with the same
19
+ * port (::1 against 127.0.0.1), can't relay the probe to the real host and hand its proof back: a proof made for one
20
+ * endpoint never verifies for another. The token itself never leaves; thincall.ts computes the same value from the socket
21
+ * it connected to and sends the token only to a host that proves it for that endpoint.
22
+ */
23
+ export declare function hostProof(token: string, challenge: string, address: string, port: number): string;
24
+ /** What goes back as JSON: the answer's text, whether it is a refusal, and the first picture when there is one. */
25
+ export interface ApiAnswer {
26
+ text: string;
27
+ isError: boolean;
28
+ image?: {
29
+ mimeType: string;
30
+ dataBase64: string;
31
+ };
32
+ }
33
+ export declare function toApiAnswer(result: CallToolResult): ApiAnswer;
34
+ export interface ApiRequestContext {
35
+ /** The host's token; never written into an answer. */
36
+ token: string;
37
+ /** Whether the peer is this computer. */
38
+ loopback: boolean;
39
+ /** Undefined on a host that doesn't serve the thin call. */
40
+ handler: ApiHandler | undefined;
41
+ }
42
+ /** Answers `/api/<tool>`; false for any other path. Checks run in the order this computer, method, token. */
43
+ export declare function handleApi(req: IncomingMessage, res: ServerResponse, context: ApiRequestContext): boolean;