@reticlehq/server 3.8.0 → 3.8.2

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 (115) hide show
  1. package/SKILL.md +2 -2
  2. package/dist/command/cli/answers/gate-hook-message.d.ts +2 -0
  3. package/dist/command/cli/answers/gate-hook-message.js +5 -1
  4. package/dist/command/cli/auth/cloud-session.d.ts +1 -19
  5. package/dist/command/cli/auth/device-flow.d.ts +3 -37
  6. package/dist/command/cli/cli-doctor.js +30 -23
  7. package/dist/command/cli/cli-flow-commands.js +7 -1
  8. package/dist/command/cli/cli-parse-serve.d.ts +24 -0
  9. package/dist/command/cli/cli-parse-serve.js +124 -0
  10. package/dist/command/cli/cli-parse.d.ts +1 -10
  11. package/dist/command/cli/cli-parse.js +62 -121
  12. package/dist/command/cli/cli-usage.js +5 -2
  13. package/dist/command/cli/cloud-link.d.ts +1 -20
  14. package/dist/command/cli/doctor/doctor-agent-link.d.ts +23 -0
  15. package/dist/command/cli/doctor/doctor-agent-link.js +28 -0
  16. package/dist/command/cli/ports/port-holder.js +6 -1
  17. package/dist/command/cli/project-name.d.ts +1 -7
  18. package/dist/command/cli/project-name.js +1 -0
  19. package/dist/command/daemon/daemon.d.ts +6 -0
  20. package/dist/command/daemon/daemon.js +52 -2
  21. package/dist/command/daemon/win32-escape.d.ts +32 -0
  22. package/dist/command/daemon/win32-escape.js +119 -0
  23. package/dist/command/setup/bringup/dev-server-files.d.ts +1 -9
  24. package/dist/command/setup/bringup/dev-server-wait.js +5 -1
  25. package/dist/command/version/version-skew.d.ts +2 -0
  26. package/dist/command/version/version-skew.js +7 -3
  27. package/dist/features/crawl/crawl-tools.js +2 -2
  28. package/dist/features/exhaust/ledger.d.ts +15 -96
  29. package/dist/features/exhaust/ledger.js +3 -3
  30. package/dist/features/license/license.d.ts +2 -14
  31. package/dist/hooks/hook-commands.js +19 -9
  32. package/dist/judgement/capsule/capsule-store.d.ts +2 -39
  33. package/dist/language/flows/annotate-tools.js +1 -1
  34. package/dist/language/flows/fields/flow-secret-field.js +1 -1
  35. package/dist/language/flows/flow-expect-grammar.js +14 -6
  36. package/dist/language/flows/flow-lease.d.ts +27 -0
  37. package/dist/language/flows/flow-lease.js +59 -0
  38. package/dist/language/flows/flow-replay-run.d.ts +1 -87
  39. package/dist/language/flows/flow-replay-run.js +88 -283
  40. package/dist/language/flows/flow-replayable.d.ts +1 -1
  41. package/dist/language/flows/flow-start-path.d.ts +108 -0
  42. package/dist/language/flows/flow-start-path.js +313 -0
  43. package/dist/language/flows/flow-tools.d.ts +2 -23
  44. package/dist/language/flows/flow-tools.js +34 -66
  45. package/dist/language/flows/recording/flake.d.ts +3 -27
  46. package/dist/language/flows/recording/flake.js +1 -1
  47. package/dist/language/flows/stores/assertion-tiers-store.js +1 -1
  48. package/dist/machine/git-tracks.js +1 -0
  49. package/dist/memory/cloud/cloud-sync.d.ts +2 -24
  50. package/dist/memory/intent/intent-shard.d.ts +41 -266
  51. package/dist/memory/journal/envelope-store.js +1 -1
  52. package/dist/memory/journal/envelope.d.ts +6 -154
  53. package/dist/memory/journal/on-disk/ambient-file.d.ts +1 -7
  54. package/dist/memory/journal/on-disk/ambient-file.js +1 -1
  55. package/dist/memory/journal/self-observation.js +3 -1
  56. package/dist/memory/journal/session-journal.js +39 -20
  57. package/dist/portal/input/drive-error.d.ts +6 -0
  58. package/dist/portal/input/drive-error.js +9 -0
  59. package/dist/portal/input/real-input-press.d.ts +34 -0
  60. package/dist/portal/input/real-input-press.js +150 -0
  61. package/dist/portal/input/real-input.d.ts +6 -23
  62. package/dist/portal/input/real-input.js +95 -192
  63. package/dist/portal/input/viewport-tools.d.ts +19 -15
  64. package/dist/portal/pool/browser-pool.d.ts +5 -55
  65. package/dist/portal/pool/browser-pool.js +121 -100
  66. package/dist/portal/pool/pool-lease.d.ts +128 -0
  67. package/dist/portal/pool/pool-lease.js +49 -0
  68. package/dist/portal/production/production-activation.d.ts +5 -27
  69. package/dist/portal/session/control-envelope.d.ts +1 -1
  70. package/dist/portal/session/zero-install-first-call.d.ts +3 -0
  71. package/dist/portal/session/zero-install-first-call.js +33 -12
  72. package/dist/surface/mcp/mcp.d.ts +3 -3
  73. package/dist/surface/mcp/mcp.js +4 -6
  74. package/dist/surface/tools/act/act-danger.js +32 -17
  75. package/dist/surface/tools/act/durable.js +1 -1
  76. package/dist/surface/tools/act-sequence-tool.js +3 -3
  77. package/dist/surface/tools/act-tools.js +15 -16
  78. package/dist/surface/tools/agent/compact-envelope.d.ts +2 -2
  79. package/dist/surface/tools/coverage-tools.js +1 -1
  80. package/dist/surface/tools/dynamic-tools.d.ts +8 -0
  81. package/dist/surface/tools/dynamic-tools.js +36 -16
  82. package/dist/surface/tools/empty-session-list.d.ts +5 -29
  83. package/dist/surface/tools/feedback-tools.js +1 -1
  84. package/dist/surface/tools/gap-novelty.d.ts +1 -1
  85. package/dist/surface/tools/gaps/capability-absences.js +4 -3
  86. package/dist/surface/tools/harness-gate.d.ts +1 -1
  87. package/dist/surface/tools/harness-toolset.js +3 -4
  88. package/dist/surface/tools/lease-permissions.d.ts +1 -1
  89. package/dist/surface/tools/lease-readiness.d.ts +23 -1
  90. package/dist/surface/tools/lease-readiness.js +75 -9
  91. package/dist/surface/tools/lease-tools.d.ts +1 -52
  92. package/dist/surface/tools/lease-tools.js +79 -142
  93. package/dist/surface/tools/observe-tools.js +3 -1
  94. package/dist/surface/tools/read-tools.js +5 -5
  95. package/dist/surface/tools/real-input-attempt.js +70 -31
  96. package/dist/surface/tools/session-ports.d.ts +57 -0
  97. package/dist/surface/tools/session-ports.js +102 -0
  98. package/dist/surface/tools/tool-kit.d.ts +5 -3
  99. package/dist/surface/tools/tools.js +1 -1
  100. package/dist/telemetry/daemon-telemetry.d.ts +3 -1
  101. package/dist/telemetry/daemon-telemetry.js +9 -2
  102. package/dist/telemetry/telemetry.d.ts +3 -1
  103. package/dist/telemetry/telemetry.js +2 -0
  104. package/docs/agent-cheatsheet.md +12 -0
  105. package/docs/cli/gate.mdx +1 -1
  106. package/docs/cli/verify.mdx +8 -1
  107. package/docs/first-drive.md +7 -0
  108. package/docs/multi-agent-testing.md +2 -0
  109. package/docs/packages/react.mdx +14 -2
  110. package/docs/packages/vite-plugin.mdx +1 -0
  111. package/docs/predicates.mdx +6 -0
  112. package/docs/skill.md +3 -3
  113. package/docs/troubleshooting.mdx +10 -0
  114. package/docs/usage.md +1 -1
  115. package/package.json +8 -9
@@ -6,7 +6,7 @@ import type { ToolDeps } from './tool-kit.js';
6
6
  export declare const EMPTY_SESSION_LIST_OUTPUT: {
7
7
  why: z.ZodOptional<z.ZodString>;
8
8
  next_action: z.ZodOptional<z.ZodObject<{
9
- action: z.ZodNativeEnum<{
9
+ action: z.ZodEnum<{
10
10
  readonly START_DEV_SERVER: "start_dev_server";
11
11
  readonly RUN_INIT: "run_init";
12
12
  readonly OPEN_APP: "open_app";
@@ -16,44 +16,20 @@ export declare const EMPTY_SESSION_LIST_OUTPUT: {
16
16
  command: z.ZodOptional<z.ZodString>;
17
17
  port: z.ZodOptional<z.ZodNumber>;
18
18
  reason: z.ZodString;
19
- }, "strip", z.ZodTypeAny, {
20
- action: "start_dev_server" | "run_init" | "open_app" | "reopen_app" | "daemon_split";
21
- reason: string;
22
- port?: number | undefined;
23
- command?: string | undefined;
24
- }, {
25
- action: "start_dev_server" | "run_init" | "open_app" | "reopen_app" | "daemon_split";
26
- reason: string;
27
- port?: number | undefined;
28
- command?: string | undefined;
29
- }>>;
19
+ }, z.core.$strip>>;
30
20
  talk_to_us: z.ZodOptional<z.ZodString>;
31
21
  next_step: z.ZodOptional<z.ZodObject<{
32
- offered: z.ZodNativeEnum<{
22
+ offered: z.ZodEnum<{
33
23
  readonly LEASE: "lease";
34
24
  readonly INIT_CONSENT: "init_consent";
35
25
  }>;
36
26
  lease: z.ZodOptional<z.ZodString>;
37
27
  consent: z.ZodString;
38
- }, "strip", z.ZodTypeAny, {
39
- offered: "lease" | "init_consent";
40
- consent: string;
41
- lease?: string | undefined;
42
- }, {
43
- offered: "lease" | "init_consent";
44
- consent: string;
45
- lease?: string | undefined;
46
- }>>;
28
+ }, z.core.$strip>>;
47
29
  lastKnown: z.ZodOptional<z.ZodObject<{
48
30
  sessionId: z.ZodString;
49
31
  url: z.ZodString;
50
- }, "strip", z.ZodTypeAny, {
51
- sessionId: string;
52
- url: string;
53
- }, {
54
- sessionId: string;
55
- url: string;
56
- }>>;
32
+ }, z.core.$strip>>;
57
33
  };
58
34
  /**
59
35
  * The next step for the calling project when another project's tab is the one connected.
@@ -153,7 +153,7 @@ export const FEEDBACK_TOOLS = [
153
153
  accepted: z.boolean(),
154
154
  reason: z.string().optional(),
155
155
  redacted: z.array(z.string()),
156
- context: z.unknown(),
156
+ context: z.unknown().optional(),
157
157
  note: z.string(),
158
158
  },
159
159
  example: {
@@ -43,5 +43,5 @@ export declare function resetGapNovelty(): void;
43
43
  * The output-schema entry for `engineBlindSpots`, shared by every verdict tool so they cannot word
44
44
  * it two ways. See `EngineBlindSpotKind` in core.
45
45
  */
46
- export declare const engineBlindSpotsOutput: z.ZodOptional<z.ZodArray<z.ZodUnknown, "many">>;
46
+ export declare const engineBlindSpotsOutput: z.ZodOptional<z.ZodArray<z.ZodUnknown>>;
47
47
  export {};
@@ -27,9 +27,10 @@ export function capabilityAbsences(session) {
27
27
  if (false === session.captureBodies) {
28
28
  absences.push({
29
29
  capability: 'network-bodies',
30
- meaning: 'request and response bodies are not recorded, so an assertion that reads one cannot be ' +
31
- 'answered here and will be refused before it spends an action',
32
- remedy: "pass captureBodies: true to connect() in this app's Reticle setup, then reload the page. " +
30
+ meaning: 'request bodies and successful response bodies are not recorded (a failed response keeps ' +
31
+ 'its body by default), so an assertion that reads one cannot be answered here and will be ' +
32
+ 'refused before it spends an action',
33
+ remedy: "pass captureNetworkBodies: true to connect() in this app's Reticle setup, then reload the page. " +
33
34
  'Bodies can carry personal data, so this is off unless a project asks for it.',
34
35
  });
35
36
  }
@@ -35,8 +35,8 @@ export declare class HarnessNotLinkedError extends DriveRefusedError {
35
35
  who: "human";
36
36
  run: string;
37
37
  } | {
38
- tool: string;
39
38
  who: "agent";
39
+ tool: string;
40
40
  })[];
41
41
  constructor();
42
42
  }
@@ -8,7 +8,6 @@
8
8
  * agent can reach.
9
9
  */
10
10
  import { z } from 'zod';
11
- import { zodToJsonSchema } from 'zod-to-json-schema';
12
11
  import { AppRuntime, ConsequenceKind, NetInitiator, PredicateKind, ReticleTool, } from '@reticlehq/core';
13
12
  import { TOOLS } from './tools.js';
14
13
  import { runTool } from './invoke-tool.js';
@@ -98,8 +97,8 @@ const INJECTED_PARAMS = new Set(['sessionId']);
98
97
  * wedge, it would manufacture one.
99
98
  */
100
99
  const TOOL_TIMEOUT_MS = 300_000;
101
- /** What the MCP SDK passes its own converter, restated so the two surfaces cannot drift apart. */
102
- const MCP_SCHEMA_OPTIONS = { strictUnions: true, pipeStrategy: 'input' };
100
+ /** What the MCP SDK passes zod's own converter, restated so the two surfaces cannot drift apart. */
101
+ const MCP_SCHEMA_OPTIONS = { target: 'draft-7', io: 'input' };
103
102
  /** Convert one tool's zod shape into the JSON Schema the model wire wants. */
104
103
  function toHarnessTool(tool) {
105
104
  const asked = Object.fromEntries(Object.entries(tool.inputSchema).filter(([name]) => !INJECTED_PARAMS.has(name)));
@@ -115,7 +114,7 @@ function toHarnessTool(tool) {
115
114
  * argument that decides whether a drive proves anything. Definitions and refs are what every
116
115
  * agent driving Reticle over MCP already reads.
117
116
  */
118
- inputSchema: zodToJsonSchema(z.object(asked), MCP_SCHEMA_OPTIONS),
117
+ inputSchema: z.toJSONSchema(z.object(asked), MCP_SCHEMA_OPTIONS),
119
118
  };
120
119
  }
121
120
  /**
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import { z } from 'zod';
10
10
  import type { BrowserPool } from '../../portal/pool/browser-pool.js';
11
- export declare const LEASE_PERMISSIONS_ARG: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
11
+ export declare const LEASE_PERMISSIONS_ARG: z.ZodOptional<z.ZodArray<z.ZodString>>;
12
12
  type PermissionPool = Pick<BrowserPool, 'notificationPermission'>;
13
13
  /** The validated list, undefined when the caller passed none, or a refusal naming the right shape. */
14
14
  export declare function parseLeasePermissions(raw: unknown): readonly string[] | undefined;
@@ -1,7 +1,8 @@
1
1
  /**
2
2
  * Is a leased tab usable right now? The checks `reticle_lease` runs before it may say `ready: true`.
3
3
  * Presence in the sessions map is not enough: the tab has to answer, and it has to be visible.
4
- * The wait for the tab to connect is here too, with the zero-install reader for a page that stays silent.
4
+ * The wait for the tab to connect is here too, with the zero-install reader for a page that stays silent,
5
+ * and the move that takes a reused lease to the page it was asked for.
5
6
  */
6
7
  import { LeaseNotReadyReason } from '@reticlehq/core';
7
8
  /** The narrow slice of a session the probe needs. Anything that quacks like this works. */
@@ -16,6 +17,11 @@ interface ProbeableSession {
16
17
  * default `false`. The pool foregrounding the page is what covers the gap; this catches the rest.
17
18
  */
18
19
  export declare function tabHidden(session: unknown): boolean;
20
+ /**
21
+ * Why a lease that connected is not ready: `failed` when it did not answer, `tab_hidden` when it
22
+ * answers from a hidden tab, nothing when it is ready.
23
+ */
24
+ export declare function notReadyReason(answered: boolean, session: unknown, failed?: LeaseNotReadyReason): LeaseNotReadyReason | undefined;
19
25
  /**
20
26
  * Does this tab still answer?
21
27
  *
@@ -68,4 +74,20 @@ export interface LeaseReaderFailure {
68
74
  reason: LeaseNotReadyReason;
69
75
  cause: string;
70
76
  }
77
+ /**
78
+ * Move a reused lease to the page it was asked for (#1667).
79
+ *
80
+ * Reuse hands back the tab wherever the last caller left it. Answering with the requested url
81
+ * while the tab stayed elsewhere sent the next read to another page. So the tab goes there, and
82
+ * the answer waits for its SDK to come back on that page, as a minted lease's does.
83
+ *
84
+ * `undefined` when there is nothing to move: the tab is already there, or its url is unknown.
85
+ * Otherwise `navigated` says whether the tab got there, `url` is the page it is on, and `arrived`
86
+ * whether its SDK connected there within the wait.
87
+ */
88
+ export declare function moveReusedLease(tabUrl: () => string | undefined, requested: string, goto: () => Promise<boolean>, now: () => number): Promise<{
89
+ navigated: boolean;
90
+ url: string;
91
+ arrived: boolean;
92
+ } | undefined>;
71
93
  export {};
@@ -1,9 +1,10 @@
1
1
  /**
2
2
  * Is a leased tab usable right now? The checks `reticle_lease` runs before it may say `ready: true`.
3
3
  * Presence in the sessions map is not enough: the tab has to answer, and it has to be visible.
4
- * The wait for the tab to connect is here too, with the zero-install reader for a page that stays silent.
4
+ * The wait for the tab to connect is here too, with the zero-install reader for a page that stays silent,
5
+ * and the move that takes a reused lease to the page it was asked for.
5
6
  */
6
- import { LeaseNotReadyReason, ReticleCommand } from '@reticlehq/core';
7
+ import { LeaseNotReadyReason, ReticleCommand, RETICLE_URL_PARAM } from '@reticlehq/core';
7
8
  import { NotHtmlDocumentError } from '../../portal/pool/zero-install.js';
8
9
  /**
9
10
  * How long a liveness probe waits for the tab to say anything at all.
@@ -25,6 +26,16 @@ export function tabHidden(session) {
25
26
  'object' === typeof session &&
26
27
  true === session.info?.().hidden);
27
28
  }
29
+ /**
30
+ * Why a lease that connected is not ready: `failed` when it did not answer, `tab_hidden` when it
31
+ * answers from a hidden tab, nothing when it is ready.
32
+ */
33
+ export function notReadyReason(answered, session, failed = LeaseNotReadyReason.SDK_STOPPED_ANSWERING) {
34
+ if (!answered) {
35
+ return failed;
36
+ }
37
+ return tabHidden(session) ? LeaseNotReadyReason.TAB_HIDDEN : undefined;
38
+ }
28
39
  /**
29
40
  * Does this tab still answer?
30
41
  *
@@ -47,8 +58,9 @@ export function tabHidden(session) {
47
58
  */
48
59
  export async function probeLeaseAlive(session, timeoutMs = LEASE_PROBE_TIMEOUT_MS) {
49
60
  const send = session?.command;
50
- if (send === undefined)
61
+ if (send === undefined) {
51
62
  return true;
63
+ }
52
64
  try {
53
65
  await send.call(session, ReticleCommand.CAPABILITIES, {}, timeoutMs);
54
66
  return true;
@@ -70,8 +82,9 @@ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
70
82
  */
71
83
  export async function waitForLeasedSession(isConnected, sleeper = sleep, attempts = LEASE_READY_ATTEMPTS, pollMs = LEASE_READY_POLL_MS) {
72
84
  for (let i = 0; i < attempts; i++) {
73
- if (isConnected())
85
+ if (isConnected()) {
74
86
  return true;
87
+ }
75
88
  await sleeper(pollMs);
76
89
  }
77
90
  return isConnected();
@@ -86,8 +99,9 @@ export async function waitForLeasedSession(isConnected, sleeper = sleep, attempt
86
99
  * that stayed silent through the whole readiness wait is the one that gets a reader.
87
100
  */
88
101
  export async function connectOrInject(lease, isConnected, wait = waitForLeasedSession, graceRounds = LEASE_LOADING_GRACE_ROUNDS) {
89
- if (await wait(isConnected))
102
+ if (await wait(isConnected)) {
90
103
  return { ready: true, zeroInstall: false };
104
+ }
91
105
  let injected;
92
106
  try {
93
107
  injected = true === (await lease.injectReader?.());
@@ -97,20 +111,24 @@ export async function connectOrInject(lease, isConnected, wait = waitForLeasedSe
97
111
  await lease.release?.().catch(() => undefined);
98
112
  return { ready: false, zeroInstall: false, readerFailure: readerFailureOf(err) };
99
113
  }
100
- if (injected && (await wait(isConnected)))
114
+ if (injected && (await wait(isConnected))) {
101
115
  return { ready: true, zeroInstall: true };
116
+ }
102
117
  // A slow first dev compile can hold the document past both waits, and its app connects a moment
103
118
  // later (#1555). Keep waiting while the page itself says it is still loading, bounded so a page
104
119
  // that never finishes cannot hold the acquire forever.
105
120
  for (let round = 0; round < graceRounds; round++) {
106
- if (!(await pageStillLoading(lease)))
121
+ if (!(await pageStillLoading(lease))) {
107
122
  break;
108
- if (await wait(isConnected))
123
+ }
124
+ if (await wait(isConnected)) {
109
125
  return { ready: true, zeroInstall: injected };
126
+ }
110
127
  }
111
128
  // Re-check right before answering: a connect that landed during the last loading probe counts.
112
- if (isConnected())
129
+ if (isConnected()) {
113
130
  return { ready: true, zeroInstall: injected };
131
+ }
114
132
  return (await pageStillLoading(lease))
115
133
  ? { ready: false, zeroInstall: false, stillLoading: true }
116
134
  : { ready: false, zeroInstall: false };
@@ -137,3 +155,51 @@ function readerFailureOf(err) {
137
155
  cause,
138
156
  };
139
157
  }
158
+ /** How long a moved lease's SDK gets to come back on the new page: the mint path's wait. */
159
+ const REUSED_ARRIVAL_MS = LEASE_READY_ATTEMPTS * LEASE_READY_POLL_MS;
160
+ /** A URL as a page: without Reticle's own params or the fragment. Undefined when it is not a URL. */
161
+ function pageOf(url) {
162
+ if (url === undefined) {
163
+ return undefined;
164
+ }
165
+ try {
166
+ const u = new URL(url);
167
+ for (const param of Object.values(RETICLE_URL_PARAM)) {
168
+ u.searchParams.delete(param);
169
+ }
170
+ u.hash = '';
171
+ return u.href;
172
+ }
173
+ catch {
174
+ return undefined;
175
+ }
176
+ }
177
+ /**
178
+ * Move a reused lease to the page it was asked for (#1667).
179
+ *
180
+ * Reuse hands back the tab wherever the last caller left it. Answering with the requested url
181
+ * while the tab stayed elsewhere sent the next read to another page. So the tab goes there, and
182
+ * the answer waits for its SDK to come back on that page, as a minted lease's does.
183
+ *
184
+ * `undefined` when there is nothing to move: the tab is already there, or its url is unknown.
185
+ * Otherwise `navigated` says whether the tab got there, `url` is the page it is on, and `arrived`
186
+ * whether its SDK connected there within the wait.
187
+ */
188
+ export async function moveReusedLease(tabUrl, requested, goto, now) {
189
+ const from = tabUrl();
190
+ const target = pageOf(requested);
191
+ if (pageOf(from) === undefined || target === undefined || pageOf(from) === target) {
192
+ return undefined;
193
+ }
194
+ const went = await Promise.resolve()
195
+ .then(goto)
196
+ .catch(() => false);
197
+ if (!went) {
198
+ return { navigated: false, url: from ?? requested, arrived: true };
199
+ }
200
+ const start = now();
201
+ while (pageOf(tabUrl()) !== target && now() - start < REUSED_ARRIVAL_MS) {
202
+ await sleep(LEASE_READY_POLL_MS);
203
+ }
204
+ return { navigated: true, url: requested, arrived: pageOf(tabUrl()) === target };
205
+ }
@@ -9,14 +9,11 @@
9
9
  *
10
10
  * Attach-only: the pool drives a browser against an already-running dev server — it never starts one.
11
11
  */
12
- import type { RealInputProvider } from '../../portal/input/real-input.js';
13
- import { type StorageFixturePort } from '../../portal/input/storage-fixture.js';
14
- import { type NetworkMutationPort } from '../../portal/input/network-mutation.js';
15
- import type { Perturbation } from '@reticlehq/core';
16
12
  import { type SeedStorage } from '@reticlehq/core';
17
13
  import { HudVisibility } from '@reticlehq/core';
18
14
  import { type ToolDef, type ToolDeps } from './tool-kit.js';
19
15
  import { type BrowserPool } from '../../portal/pool/browser-pool.js';
16
+ export { sessionMutationPort, sessionPerturbationPort, suiteFixturePort, suiteFixtureSeed, } from './session-ports.js';
20
17
  /**
21
18
  * Append Reticle identity params (__reticle_session, optional __reticle_project) to a URL so the app's own SDK
22
19
  * adopts them on connect. Pure; falls back to plain concatenation if the URL can't be parsed.
@@ -101,51 +98,3 @@ export declare const LEASE_ACQUIRE_TOOL: ToolDef;
101
98
  */
102
99
  export declare function releaseLease(deps: ToolDeps, pool: BrowserPool, sessionId: string): Promise<number>;
103
100
  export declare const LEASE_TOOLS: ToolDef[];
104
- /**
105
- * The state a suite should boot its flows from: whatever the agent is already sitting in.
106
- *
107
- * This is the join the fixture work was building toward. A suite's flows each start from cold, so
108
- * fifty of them prove the login works fifty times — and the flow that LOGS OUT leaves every flow
109
- * after it signed out, which no navigation repairs, because the problem is not where the subject is
110
- * but what it holds. A seed is applied to an isolated context BEFORE the first navigation, which is
111
- * exactly and only when a fixture can work.
112
- *
113
- * Best-effort, deliberately. A fixture is an OPTIMISATION over running from cold, and running from
114
- * cold is correct: a suite that refused to start because a cookie jar could not be read would have
115
- * traded a slow answer for no answer. Every "no" here — no provider, no storage support, nothing
116
- * driven, a browser that threw, nothing worth seeding — produces the same honest `undefined`, and
117
- * the suite runs exactly as it did before any of this existed.
118
- */
119
- export declare function suiteFixtureSeed(realInput: RealInputProvider | undefined, appUrl: string): Promise<SeedStorage | undefined>;
120
- /**
121
- * A way to make this session's page SLOW on purpose, or nothing.
122
- *
123
- * The third of these seams, for the same reason as the other two: a feature reaching into the input
124
- * layer directly is a feature depending on a driver, and the boundary guard asks about it.
125
- *
126
- * Installs delays and NOTHING else. A rule that carried a status or a body would substitute a
127
- * response the server never sent, and an app raced against invented data produces invented races —
128
- * a fabricated defect handed to somebody at 3am, which is worse than finding nothing.
129
- */
130
- export declare function sessionPerturbationPort(realInput: RealInputProvider | undefined, appUrl: string | undefined): Promise<{
131
- slow(rules: readonly Perturbation[]): Promise<void>;
132
- clear(): Promise<void>;
133
- } | undefined>;
134
- /**
135
- * Save/restore for this session's page, or nothing.
136
- *
137
- * The same job as `suiteFixtureSeed` next door, stopping one step earlier: that one captures and
138
- * converts, this hands back the PORT so a caller can re-apply what it captured later. It lives here
139
- * for the reason written above — a feature reaching into the input layer directly is a feature
140
- * depending on a driver, and the boundary guard asks about it. It asked.
141
- */
142
- export declare function suiteFixturePort(realInput: RealInputProvider | undefined, appUrl: string | undefined): Promise<StorageFixturePort | undefined>;
143
- /**
144
- * A way to break this session's page, or nothing.
145
- *
146
- * Sits beside `suiteFixtureSeed` because it is the same shape of job: turning a provider capability
147
- * into something a feature can use, on the one side of the graph that is allowed to know about both.
148
- * A flow tool reaching into the input layer directly would be a feature depending on a driver, which
149
- * is the reach the boundary guard exists to ask about.
150
- */
151
- export declare function sessionMutationPort(realInput: RealInputProvider | undefined, appUrl: string | undefined): Promise<NetworkMutationPort | undefined>;