zidane 5.13.26 → 5.14.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 (145) hide show
  1. package/dist/{acp-CjAoILwj.js → acp-DgKEJH3P.js} +7 -7
  2. package/dist/{acp-CjAoILwj.js.map → acp-DgKEJH3P.js.map} +1 -1
  3. package/dist/acp-cli.js +11 -6
  4. package/dist/acp-cli.js.map +1 -1
  5. package/dist/acp.d.ts +2 -2
  6. package/dist/acp.js +1 -1
  7. package/dist/{tools-B32lZXLE.js → agent-B-cKanSC.js} +8035 -9459
  8. package/dist/agent-B-cKanSC.js.map +1 -0
  9. package/dist/{agent-DQIL5BFk.d.ts → agent-BAgOgS37.d.ts} +367 -208
  10. package/dist/agent-BAgOgS37.d.ts.map +1 -0
  11. package/dist/agent.d.ts +3 -0
  12. package/dist/agent.js +5 -0
  13. package/dist/anthropic-RGqsJlC8.js +807 -0
  14. package/dist/anthropic-RGqsJlC8.js.map +1 -0
  15. package/dist/{atomic-write-Bgtr5JPu.js → atomic-write-B7zr1ddF.js} +2 -2
  16. package/dist/{atomic-write-Bgtr5JPu.js.map → atomic-write-B7zr1ddF.js.map} +1 -1
  17. package/dist/{auth-DPrSP1YV.js → auth-C-ms5N2x.js} +33 -5
  18. package/dist/{auth-DPrSP1YV.js.map → auth-C-ms5N2x.js.map} +1 -1
  19. package/dist/cache-telemetry-BKAwsNxm.js +169 -0
  20. package/dist/cache-telemetry-BKAwsNxm.js.map +1 -0
  21. package/dist/chat/pure.d.ts +3 -3
  22. package/dist/chat/pure.js +1 -1
  23. package/dist/chat.d.ts +21 -7
  24. package/dist/chat.d.ts.map +1 -1
  25. package/dist/chat.js +30 -5
  26. package/dist/chat.js.map +1 -1
  27. package/dist/contexts/daytona.d.ts +1 -1
  28. package/dist/contexts/docker.js +0 -1
  29. package/dist/contexts/docker.js.map +1 -1
  30. package/dist/contexts/e2b.d.ts +1 -1
  31. package/dist/errors-CkTvg97v.d.ts +203 -0
  32. package/dist/errors-CkTvg97v.d.ts.map +1 -0
  33. package/dist/errors.d.ts +3 -0
  34. package/dist/errors.js +3 -0
  35. package/dist/eval.d.ts +1 -1
  36. package/dist/eval.js +2 -2
  37. package/dist/headless.d.ts +1 -1
  38. package/dist/headless.js +406 -1
  39. package/dist/headless.js.map +1 -0
  40. package/dist/{index-YY3vp2F2.d.ts → index-CLuLFFLa.d.ts} +88 -418
  41. package/dist/index-CLuLFFLa.d.ts.map +1 -0
  42. package/dist/{index-C5qw3pj7.d.ts → index-CgBIl2mX.d.ts} +2 -2
  43. package/dist/{index-C5qw3pj7.d.ts.map → index-CgBIl2mX.d.ts.map} +1 -1
  44. package/dist/index.d.ts +9 -5
  45. package/dist/index.js +113 -167
  46. package/dist/index.js.map +1 -1
  47. package/dist/{logger-C2ngE8CY.d.ts → logger-CJ-lpKPy.d.ts} +2 -2
  48. package/dist/{logger-C2ngE8CY.d.ts.map → logger-CJ-lpKPy.d.ts.map} +1 -1
  49. package/dist/mcp.d.ts +1 -1
  50. package/dist/messages-YZQLKaz2.js +1157 -0
  51. package/dist/messages-YZQLKaz2.js.map +1 -0
  52. package/dist/oauth-8LqbeI_Q.js +292 -0
  53. package/dist/oauth-8LqbeI_Q.js.map +1 -0
  54. package/dist/{messages-Iy_vEycX.js → openai-compat-0Y7jcncn.js} +27 -1379
  55. package/dist/openai-compat-0Y7jcncn.js.map +1 -0
  56. package/dist/output/stream-json.d.ts +2 -2
  57. package/dist/output/stream-json.js +1 -1
  58. package/dist/output/terminal.d.ts +2 -2
  59. package/dist/{presets-B9nDwmaz.js → presets-Pr02ZNcy.js} +3 -2
  60. package/dist/{presets-B9nDwmaz.js.map → presets-Pr02ZNcy.js.map} +1 -1
  61. package/dist/presets.d.ts +2 -2
  62. package/dist/presets.js +1 -1
  63. package/dist/prompt.d.ts +2 -0
  64. package/dist/prompt.js +210 -0
  65. package/dist/prompt.js.map +1 -0
  66. package/dist/providers/anthropic.d.ts +2 -0
  67. package/dist/providers/anthropic.js +2 -0
  68. package/dist/providers/arcee.d.ts +2 -0
  69. package/dist/providers/arcee.js +42 -0
  70. package/dist/providers/arcee.js.map +1 -0
  71. package/dist/providers/baseten.d.ts +2 -0
  72. package/dist/providers/baseten.js +66 -0
  73. package/dist/providers/baseten.js.map +1 -0
  74. package/dist/providers/cerebras.d.ts +2 -0
  75. package/dist/providers/cerebras.js +31 -0
  76. package/dist/providers/cerebras.js.map +1 -0
  77. package/dist/providers/local.d.ts +2 -0
  78. package/dist/providers/local.js +44 -0
  79. package/dist/providers/local.js.map +1 -0
  80. package/dist/providers/openai-compat.d.ts +2 -0
  81. package/dist/providers/openai-compat.js +2 -0
  82. package/dist/providers/openai.d.ts +2 -0
  83. package/dist/providers/openai.js +504 -0
  84. package/dist/providers/openai.js.map +1 -0
  85. package/dist/providers/openrouter.d.ts +2 -0
  86. package/dist/providers/openrouter.js +52 -0
  87. package/dist/providers/openrouter.js.map +1 -0
  88. package/dist/providers/xai.d.ts +2 -0
  89. package/dist/providers/xai.js +2 -0
  90. package/dist/providers-DgmdYGKm.js +168 -0
  91. package/dist/providers-DgmdYGKm.js.map +1 -0
  92. package/dist/providers.d.ts +1 -1
  93. package/dist/providers.js +10 -2
  94. package/dist/restate.d.ts +1 -1
  95. package/dist/run-summary-DAnBZnrt.d.ts +249 -0
  96. package/dist/run-summary-DAnBZnrt.d.ts.map +1 -0
  97. package/dist/run-summary-nD3IQ4ZQ.js +253 -0
  98. package/dist/run-summary-nD3IQ4ZQ.js.map +1 -0
  99. package/dist/session/sqlite.d.ts +1 -1
  100. package/dist/{session-CiA1_8SB.js → session-CqrAFAKJ.js} +2 -2
  101. package/dist/{session-CiA1_8SB.js.map → session-CqrAFAKJ.js.map} +1 -1
  102. package/dist/session.d.ts +1 -1
  103. package/dist/session.js +2 -2
  104. package/dist/skills.d.ts +2 -2
  105. package/dist/system-prompt-BlsdjcUi.d.ts +139 -0
  106. package/dist/system-prompt-BlsdjcUi.d.ts.map +1 -0
  107. package/dist/timeout-CpFm0jJ6.d.ts +10 -0
  108. package/dist/timeout-CpFm0jJ6.d.ts.map +1 -0
  109. package/dist/timeout-kGGSXagK.js +84 -0
  110. package/dist/timeout-kGGSXagK.js.map +1 -0
  111. package/dist/{tool-formatters-w5oaoCS4.d.ts → tool-formatters-Ch8oRpYR.d.ts} +2 -2
  112. package/dist/{tool-formatters-w5oaoCS4.d.ts.map → tool-formatters-Ch8oRpYR.d.ts.map} +1 -1
  113. package/dist/tools/fetch-url.d.ts +1 -1
  114. package/dist/tools/web-search.d.ts +1 -1
  115. package/dist/tools-00_Nqazv.js +1689 -0
  116. package/dist/tools-00_Nqazv.js.map +1 -0
  117. package/dist/tools.d.ts +2 -2
  118. package/dist/tools.js +2 -1
  119. package/dist/{transcript-anchors-BUtOd-qa.js → transcript-anchors-BUmvPnis.js} +10 -9
  120. package/dist/{transcript-anchors-BUtOd-qa.js.map → transcript-anchors-BUmvPnis.js.map} +1 -1
  121. package/dist/{transcript-anchors-BJ-ESWnm.d.ts → transcript-anchors-CL9UM_M4.d.ts} +4 -4
  122. package/dist/{transcript-anchors-BJ-ESWnm.d.ts.map → transcript-anchors-CL9UM_M4.d.ts.map} +1 -1
  123. package/dist/tui.d.ts +3 -3
  124. package/dist/tui.js +38 -13
  125. package/dist/tui.js.map +1 -1
  126. package/dist/{turn-operations-BSSQHNq1.d.ts → turn-operations-Cj6v_ypW.d.ts} +3 -3
  127. package/dist/{turn-operations-BSSQHNq1.d.ts.map → turn-operations-Cj6v_ypW.d.ts.map} +1 -1
  128. package/dist/{turn-operations-B_XeuNp-.js → turn-operations-tG0vuBNc.js} +2 -2
  129. package/dist/{turn-operations-B_XeuNp-.js.map → turn-operations-tG0vuBNc.js.map} +1 -1
  130. package/dist/types-CyVGdbia.js.map +1 -1
  131. package/dist/types.d.ts +4 -3
  132. package/dist/xai-tPdbAGkq.js +379 -0
  133. package/dist/xai-tPdbAGkq.js.map +1 -0
  134. package/docs/ARCHITECTURE.md +4 -2
  135. package/docs/CHAT.md +4 -0
  136. package/docs/SKILL.md +31 -5
  137. package/package.json +63 -1
  138. package/dist/agent-DQIL5BFk.d.ts.map +0 -1
  139. package/dist/headless-2SH7dvoW.js +0 -656
  140. package/dist/headless-2SH7dvoW.js.map +0 -1
  141. package/dist/index-YY3vp2F2.d.ts.map +0 -1
  142. package/dist/messages-Iy_vEycX.js.map +0 -1
  143. package/dist/providers-BMw1D_lj.js +0 -2332
  144. package/dist/providers-BMw1D_lj.js.map +0 -1
  145. package/dist/tools-B32lZXLE.js.map +0 -1
@@ -0,0 +1,168 @@
1
+ import { m as openaiCompat } from "./openai-compat-0Y7jcncn.js";
2
+ import { i as resolveOAuthApiKey } from "./oauth-8LqbeI_Q.js";
3
+ import { r as generatePkce } from "./xai-tPdbAGkq.js";
4
+ //#region src/chat/oauth-page/cursor.ts
5
+ /** pi-ai / zidane OAuth provider id. Also the credentials-file key. */
6
+ const CURSOR_OAUTH_PROVIDER_ID = "cursor";
7
+ const CURSOR_LOGIN_URL = "https://cursor.com/loginDeepControl";
8
+ const CURSOR_POLL_URL = "https://api2.cursor.sh/auth/poll";
9
+ const CURSOR_REFRESH_URL = "https://api2.cursor.sh/auth/exchange_user_api_key";
10
+ const POLL_MAX_ATTEMPTS = 150;
11
+ const POLL_BASE_DELAY_MS = 1e3;
12
+ const POLL_MAX_DELAY_MS = 1e4;
13
+ const POLL_BACKOFF_MULTIPLIER = 1.2;
14
+ const POLL_MAX_CONSECUTIVE_ERRORS = 3;
15
+ /** Fallback lifetime when the JWT carries no `exp`. */
16
+ const DEFAULT_TOKEN_TTL_MS = 3600 * 1e3;
17
+ /** Refresh slightly early so requests don't race expiry. */
18
+ const TOKEN_EXPIRY_SKEW_MS = 300 * 1e3;
19
+ /**
20
+ * Derive expiry (epoch ms) from a JWT's `exp` claim, minus a safety skew.
21
+ * Returns `now + 1h` for malformed tokens so a missing claim never wedges
22
+ * refresh into an immediate-expire loop.
23
+ */
24
+ function cursorTokenExpiry(token) {
25
+ try {
26
+ const parts = token.split(".");
27
+ const payload = parts[1];
28
+ if (parts.length !== 3 || !payload) return Date.now() + DEFAULT_TOKEN_TTL_MS;
29
+ const json = JSON.parse(atob(payload.replace(/-/g, "+").replace(/_/g, "/")));
30
+ if (typeof json.exp === "number") return json.exp * 1e3 - TOKEN_EXPIRY_SKEW_MS;
31
+ } catch {}
32
+ return Date.now() + DEFAULT_TOKEN_TTL_MS;
33
+ }
34
+ function delay(ms) {
35
+ return new Promise((r) => setTimeout(r, ms));
36
+ }
37
+ /**
38
+ * Poll Cursor's auth endpoint until login completes. `404` means the user
39
+ * hasn't finished the browser flow yet; anything else non-2xx is a hard error.
40
+ */
41
+ async function pollForTokens(uuid, verifier, callbacks) {
42
+ let wait = POLL_BASE_DELAY_MS;
43
+ let consecutiveErrors = 0;
44
+ for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {
45
+ if (callbacks.signal?.aborted) throw new Error("Cursor login aborted");
46
+ await delay(wait);
47
+ try {
48
+ const url = `${CURSOR_POLL_URL}?uuid=${encodeURIComponent(uuid)}&verifier=${encodeURIComponent(verifier)}`;
49
+ const response = await fetch(url, { signal: callbacks.signal });
50
+ if (response.status === 404) {
51
+ consecutiveErrors = 0;
52
+ wait = Math.min(wait * POLL_BACKOFF_MULTIPLIER, POLL_MAX_DELAY_MS);
53
+ continue;
54
+ }
55
+ if (response.ok) {
56
+ const data = await response.json();
57
+ if (!data.accessToken || !data.refreshToken) throw new Error(`Cursor poll response missing tokens: ${JSON.stringify(data)}`);
58
+ return {
59
+ accessToken: data.accessToken,
60
+ refreshToken: data.refreshToken
61
+ };
62
+ }
63
+ throw new Error(`Cursor poll failed (${response.status})`);
64
+ } catch (err) {
65
+ if (callbacks.signal?.aborted) throw new Error("Cursor login aborted");
66
+ consecutiveErrors++;
67
+ if (consecutiveErrors >= POLL_MAX_CONSECUTIVE_ERRORS) throw err instanceof Error ? err : new Error(String(err));
68
+ callbacks.onProgress?.("Waiting for Cursor login to complete…");
69
+ }
70
+ }
71
+ throw new Error("Cursor authentication timed out");
72
+ }
73
+ async function loginCursor(callbacks) {
74
+ const { verifier, challenge } = await generatePkce();
75
+ const uuid = crypto.randomUUID();
76
+ const authUrl = new URL(CURSOR_LOGIN_URL);
77
+ authUrl.searchParams.set("challenge", challenge);
78
+ authUrl.searchParams.set("uuid", uuid);
79
+ authUrl.searchParams.set("mode", "login");
80
+ authUrl.searchParams.set("redirectTarget", "cli");
81
+ callbacks.onAuth({
82
+ url: authUrl.toString(),
83
+ instructions: "A browser window should open. Complete login in Cursor to finish."
84
+ });
85
+ const tokens = await pollForTokens(uuid, verifier, callbacks);
86
+ return {
87
+ access: tokens.accessToken,
88
+ refresh: tokens.refreshToken,
89
+ expires: cursorTokenExpiry(tokens.accessToken)
90
+ };
91
+ }
92
+ async function refreshCursorToken(credentials) {
93
+ const response = await fetch(CURSOR_REFRESH_URL, {
94
+ method: "POST",
95
+ headers: {
96
+ "Authorization": `Bearer ${credentials.refresh}`,
97
+ "Content-Type": "application/json"
98
+ },
99
+ body: "{}"
100
+ });
101
+ if (!response.ok) {
102
+ const text = await response.text().catch(() => "");
103
+ throw new Error(`Cursor token refresh failed (${response.status}): ${text || response.statusText}`);
104
+ }
105
+ const data = await response.json();
106
+ if (!data.accessToken) throw new Error(`Cursor token refresh response missing access token: ${JSON.stringify(data)}`);
107
+ return {
108
+ access: data.accessToken,
109
+ refresh: data.refreshToken || credentials.refresh,
110
+ expires: cursorTokenExpiry(data.accessToken)
111
+ };
112
+ }
113
+ /**
114
+ * Build a Cursor `OAuthProviderInterface`. Shape matches Anthropic / Codex so
115
+ * it drops into `BUILTIN_PROVIDERS` and `src/auth.ts` unchanged.
116
+ *
117
+ * No `renderPage` parameter: Cursor's poll flow has no local callback server,
118
+ * so there is no post-redirect page to theme.
119
+ */
120
+ function createCursorOAuthProvider() {
121
+ return {
122
+ id: CURSOR_OAUTH_PROVIDER_ID,
123
+ name: "Cursor",
124
+ usesCallbackServer: false,
125
+ login: loginCursor,
126
+ refreshToken: refreshCursorToken,
127
+ getApiKey: (credentials) => credentials.access
128
+ };
129
+ }
130
+ //#endregion
131
+ //#region src/providers/cursor.ts
132
+ const DEFAULT_MODEL = "claude-4.6-sonnet";
133
+ const NOT_IMPLEMENTED_MESSAGE = "Cursor OAuth login works, but inference over Cursor is not implemented yet. Cursor uses a protobuf/HTTP-2 agent protocol (not an OpenAI-compatible API), so the streaming transport still needs to be ported. Use another provider for now.";
134
+ function cursor(params) {
135
+ const defaultModel = params?.defaultModel || DEFAULT_MODEL;
136
+ const base = openaiCompat({
137
+ name: "cursor",
138
+ apiKey: params?.apiKey ?? "oauth",
139
+ baseURL: "https://api2.cursor.sh",
140
+ defaultModel,
141
+ capabilities: {
142
+ vision: true,
143
+ imageInToolResult: false
144
+ },
145
+ extraHeaders: params?.extraHeaders
146
+ });
147
+ return {
148
+ ...base,
149
+ meta: {
150
+ ...base.meta,
151
+ defaultModel
152
+ },
153
+ async stream(options, callbacks) {
154
+ await resolveOAuthApiKey({
155
+ provider: "cursor",
156
+ providerId: CURSOR_OAUTH_PROVIDER_ID,
157
+ params,
158
+ missingError: "No Cursor credentials found. Run `bun run auth --cursor` first.",
159
+ refreshError: (reason) => `Cursor OAuth token refresh failed. Run \`bun run auth --cursor\` again. ${reason}`
160
+ }, callbacks);
161
+ throw new Error(NOT_IMPLEMENTED_MESSAGE);
162
+ }
163
+ };
164
+ }
165
+ //#endregion
166
+ export { createCursorOAuthProvider as n, cursor as t };
167
+
168
+ //# sourceMappingURL=providers-DgmdYGKm.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"providers-DgmdYGKm.js","names":[],"sources":["../src/chat/oauth-page/cursor.ts","../src/providers/cursor.ts"],"sourcesContent":["/**\n * Cursor OAuth flow.\n *\n * Unlike Anthropic / OpenAI Codex (loopback-redirect PKCE), Cursor uses a\n * **poll-based** PKCE flow with no local callback server:\n *\n * 1. Generate a PKCE verifier + challenge and a random UUID.\n * 2. Open the browser to `cursor.com/loginDeepControl?challenge&uuid&mode&redirectTarget`.\n * 3. Poll `api2.cursor.sh/auth/poll?uuid&verifier` until tokens come back\n * (HTTP 404 = \"not ready yet\", keep polling with backoff).\n * 4. Refresh via `POST api2.cursor.sh/auth/exchange_user_api_key` with\n * `Authorization: Bearer <refresh>`.\n *\n * Token expiry is derived from the access token's JWT `exp` claim (minus a\n * 5-minute safety margin), falling back to +1h when the claim is missing.\n *\n * Flow adapted from https://github.com/ndraiman/pi-cursor-provider, itself\n * derived from https://github.com/ephraimduncan/opencode-cursor.\n *\n * Cursor's auth + inference protocol is unofficial and undocumented — re-verify\n * the endpoints/params below if login starts failing.\n */\n\nimport type {\n OAuthCredentials,\n OAuthLoginCallbacks,\n OAuthProviderInterface,\n} from '@earendil-works/pi-ai/oauth'\nimport { generatePkce } from './pkce'\n\n/** pi-ai / zidane OAuth provider id. Also the credentials-file key. */\nexport const CURSOR_OAUTH_PROVIDER_ID = 'cursor'\n\nconst CURSOR_LOGIN_URL = 'https://cursor.com/loginDeepControl'\nconst CURSOR_POLL_URL = 'https://api2.cursor.sh/auth/poll'\nconst CURSOR_REFRESH_URL = 'https://api2.cursor.sh/auth/exchange_user_api_key'\n\nconst POLL_MAX_ATTEMPTS = 150\nconst POLL_BASE_DELAY_MS = 1000\nconst POLL_MAX_DELAY_MS = 10_000\nconst POLL_BACKOFF_MULTIPLIER = 1.2\nconst POLL_MAX_CONSECUTIVE_ERRORS = 3\n\n/** Fallback lifetime when the JWT carries no `exp`. */\nconst DEFAULT_TOKEN_TTL_MS = 3600 * 1000\n/** Refresh slightly early so requests don't race expiry. */\nconst TOKEN_EXPIRY_SKEW_MS = 5 * 60 * 1000\n\ninterface CursorTokenResponse {\n accessToken: string\n refreshToken: string\n}\n\n/**\n * Derive expiry (epoch ms) from a JWT's `exp` claim, minus a safety skew.\n * Returns `now + 1h` for malformed tokens so a missing claim never wedges\n * refresh into an immediate-expire loop.\n */\nexport function cursorTokenExpiry(token: string): number {\n try {\n const parts = token.split('.')\n const payload = parts[1]\n if (parts.length !== 3 || !payload)\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n\n const json = JSON.parse(atob(payload.replace(/-/g, '+').replace(/_/g, '/'))) as { exp?: unknown }\n if (typeof json.exp === 'number')\n return json.exp * 1000 - TOKEN_EXPIRY_SKEW_MS\n }\n catch {\n // fall through to default\n }\n return Date.now() + DEFAULT_TOKEN_TTL_MS\n}\n\nfunction delay(ms: number): Promise<void> {\n return new Promise(r => setTimeout(r, ms))\n}\n\n/**\n * Poll Cursor's auth endpoint until login completes. `404` means the user\n * hasn't finished the browser flow yet; anything else non-2xx is a hard error.\n */\nasync function pollForTokens(\n uuid: string,\n verifier: string,\n callbacks: OAuthLoginCallbacks,\n): Promise<CursorTokenResponse> {\n let wait = POLL_BASE_DELAY_MS\n let consecutiveErrors = 0\n\n for (let attempt = 0; attempt < POLL_MAX_ATTEMPTS; attempt++) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n\n await delay(wait)\n\n try {\n const url = `${CURSOR_POLL_URL}?uuid=${encodeURIComponent(uuid)}&verifier=${encodeURIComponent(verifier)}`\n const response = await fetch(url, { signal: callbacks.signal })\n\n if (response.status === 404) {\n consecutiveErrors = 0\n wait = Math.min(wait * POLL_BACKOFF_MULTIPLIER, POLL_MAX_DELAY_MS)\n continue\n }\n\n if (response.ok) {\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken || !data.refreshToken)\n throw new Error(`Cursor poll response missing tokens: ${JSON.stringify(data)}`)\n return { accessToken: data.accessToken, refreshToken: data.refreshToken }\n }\n\n throw new Error(`Cursor poll failed (${response.status})`)\n }\n catch (err) {\n if (callbacks.signal?.aborted)\n throw new Error('Cursor login aborted')\n consecutiveErrors++\n if (consecutiveErrors >= POLL_MAX_CONSECUTIVE_ERRORS)\n throw err instanceof Error ? err : new Error(String(err))\n callbacks.onProgress?.('Waiting for Cursor login to complete…')\n }\n }\n\n throw new Error('Cursor authentication timed out')\n}\n\nexport async function loginCursor(callbacks: OAuthLoginCallbacks): Promise<OAuthCredentials> {\n const { verifier, challenge } = await generatePkce()\n const uuid = crypto.randomUUID()\n\n const authUrl = new URL(CURSOR_LOGIN_URL)\n authUrl.searchParams.set('challenge', challenge)\n authUrl.searchParams.set('uuid', uuid)\n authUrl.searchParams.set('mode', 'login')\n authUrl.searchParams.set('redirectTarget', 'cli')\n\n callbacks.onAuth({\n url: authUrl.toString(),\n instructions: 'A browser window should open. Complete login in Cursor to finish.',\n })\n\n const tokens = await pollForTokens(uuid, verifier, callbacks)\n\n return {\n access: tokens.accessToken,\n refresh: tokens.refreshToken,\n expires: cursorTokenExpiry(tokens.accessToken),\n }\n}\n\nexport async function refreshCursorToken(credentials: OAuthCredentials): Promise<OAuthCredentials> {\n const response = await fetch(CURSOR_REFRESH_URL, {\n method: 'POST',\n headers: {\n 'Authorization': `Bearer ${credentials.refresh}`,\n 'Content-Type': 'application/json',\n },\n body: '{}',\n })\n\n if (!response.ok) {\n const text = await response.text().catch(() => '')\n throw new Error(`Cursor token refresh failed (${response.status}): ${text || response.statusText}`)\n }\n\n const data = await response.json() as Partial<CursorTokenResponse>\n if (!data.accessToken)\n throw new Error(`Cursor token refresh response missing access token: ${JSON.stringify(data)}`)\n\n return {\n access: data.accessToken,\n // Cursor may omit a rotated refresh token — keep the existing one.\n refresh: data.refreshToken || credentials.refresh,\n expires: cursorTokenExpiry(data.accessToken),\n }\n}\n\n/**\n * Build a Cursor `OAuthProviderInterface`. Shape matches Anthropic / Codex so\n * it drops into `BUILTIN_PROVIDERS` and `src/auth.ts` unchanged.\n *\n * No `renderPage` parameter: Cursor's poll flow has no local callback server,\n * so there is no post-redirect page to theme.\n */\nexport function createCursorOAuthProvider(): OAuthProviderInterface {\n return {\n id: CURSOR_OAUTH_PROVIDER_ID,\n name: 'Cursor',\n usesCallbackServer: false,\n login: loginCursor,\n refreshToken: refreshCursorToken,\n getApiKey: credentials => credentials.access,\n }\n}\n","import type { Provider, StreamCallbacks } from '.'\nimport { CURSOR_OAUTH_PROVIDER_ID } from '../chat/oauth-page/cursor'\nimport { resolveOAuthApiKey } from './oauth'\nimport { openaiCompat } from './openai-compat'\n\n/**\n * Cursor provider (OAuth).\n *\n * Auth is fully wired: `bun run auth --cursor` (or the TUI wizard) logs in via\n * Cursor's poll-based PKCE flow and persists credentials; this provider resolves\n * + refreshes the OAuth token on every turn via {@link resolveOAuthApiKey}.\n *\n * Inference is **not** wired yet. Cursor does not expose an OpenAI-compatible\n * HTTP endpoint — it speaks a protobuf/Connect agent protocol over HTTP/2 to\n * `api2.cursor.sh`. Implementing `stream()` requires porting that transport\n * (generated protobuf schemas + an HTTP/2 streaming client) in-process, which\n * is intentionally left as a follow-up. Until then `stream()` resolves the\n * token (proving auth works) and then throws a clear, actionable error.\n *\n * The `openaiCompat` base supplies the message-format helpers (`formatTools`,\n * `userMessage`, `toolResultsMessage`, …) so the provider satisfies the full\n * `Provider` contract and slots into the registry; only `stream` is overridden.\n */\nexport interface CursorParams {\n /** Bypass OAuth resolution with an explicit token (mainly for tests). */\n apiKey?: string\n defaultModel?: string\n /**\n * Extra HTTP headers for the eventual Cursor transport. Accepted for API\n * parity with the other providers and forwarded to the openai-compat base,\n * but inert until Cursor inference is implemented (the `stream` override\n * currently throws before any request is made).\n */\n extraHeaders?: Record<string, string>\n}\n\nconst DEFAULT_MODEL = 'claude-4.6-sonnet'\n\nconst NOT_IMPLEMENTED_MESSAGE\n = 'Cursor OAuth login works, but inference over Cursor is not implemented yet. '\n + 'Cursor uses a protobuf/HTTP-2 agent protocol (not an OpenAI-compatible API), '\n + 'so the streaming transport still needs to be ported. Use another provider for now.'\n\nexport function cursor(params?: CursorParams): Provider {\n const defaultModel = params?.defaultModel || DEFAULT_MODEL\n\n // Base only provides the format/serialization methods; `baseURL` is never\n // hit because we override `stream` below.\n const base = openaiCompat({\n name: 'cursor',\n apiKey: params?.apiKey ?? 'oauth',\n baseURL: 'https://api2.cursor.sh',\n defaultModel,\n capabilities: { vision: true, imageInToolResult: false },\n extraHeaders: params?.extraHeaders,\n })\n\n return {\n ...base,\n meta: { ...base.meta, defaultModel },\n async stream(options, callbacks: StreamCallbacks) {\n // Resolve (and lazily refresh) the OAuth token so auth failures surface\n // here with the right remediation, distinct from the not-implemented path.\n await resolveOAuthApiKey(\n {\n provider: 'cursor',\n providerId: CURSOR_OAUTH_PROVIDER_ID,\n params,\n missingError: 'No Cursor credentials found. Run `bun run auth --cursor` first.',\n refreshError: reason => `Cursor OAuth token refresh failed. Run \\`bun run auth --cursor\\` again. ${reason}`,\n },\n callbacks,\n )\n void options\n throw new Error(NOT_IMPLEMENTED_MESSAGE)\n },\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import { $t as cerebras, At as TurnResult, Bt as OpenAICompatAuthHeader, Ct as ProviderCapabilities, Dt as ToolCall, Et as TokenCountPayload, Ft as SchemaSanitizeResult, Gt as openaiCompat, Ht as OpenAICompatParams, It as sanitizeToolSchema, Jt as LocalParams, Kt as OpenAIParams, Lt as sanitizeToolSpecs, Mt as xai, Nt as SchemaSanitizeOptions, Ot as ToolResult, Pt as SchemaSanitizeProfile, Qt as CerebrasParams, Rt as OpenRouterParams, St as Provider, Tt as StreamOptions, Ut as classifyOpenAICompatError, Vt as OpenAICompatHttpError, Wt as mapOAIFinishReason, Xt as CursorParams, Yt as local, Zt as cursor, an as AnthropicParams, en as BasetenParams, in as arcee, jt as XaiParams, kt as ToolSpec, nn as planBasetenReasoning, on as anthropic, qt as openai, rn as ArceeParams, sn as applyAnthropicCacheBreakpoints, tn as baseten, wt as StreamCallbacks, zt as openrouter } from "./agent-DQIL5BFk.js";
1
+ import { $t as classifyOpenAICompatError, At as TurnResult, Bt as openrouter, Cn as arcee, Ct as ProviderCapabilities, Dn as anthropic, Dt as ToolCall, Et as TokenCountPayload, Ft as SchemaSanitizeResult, Gt as OpenAICompatHttpError, It as sanitizeToolSchema, Kt as OpenAICompatParams, Lt as sanitizeToolSpecs, Mt as xai, Nt as SchemaSanitizeOptions, On as applyAnthropicCacheBreakpoints, Ot as ToolResult, Pt as SchemaSanitizeProfile, Rt as OpenRouterParams, Sn as ArceeParams, St as Provider, Tn as AnthropicParams, Tt as StreamOptions, Wt as OpenAICompatAuthHeader, _n as CerebrasParams, bn as baseten, cn as OpenAIParams, dn as openai, gn as cursor, hn as CursorParams, in as openaiCompat, jt as XaiParams, kt as ToolSpec, mn as local, nn as mapOAIFinishReason, pn as LocalParams, vn as cerebras, wt as StreamCallbacks, xn as planBasetenReasoning, yn as BasetenParams } from "./agent-BAgOgS37.js";
2
2
  export { type AnthropicParams, type ArceeParams, type BasetenParams, type CerebrasParams, type CursorParams, type LocalParams, type OpenAICompatAuthHeader, OpenAICompatHttpError, type OpenAICompatParams, type OpenAIParams, type OpenRouterParams, Provider, ProviderCapabilities, type SchemaSanitizeOptions, type SchemaSanitizeProfile, type SchemaSanitizeResult, StreamCallbacks, StreamOptions, TokenCountPayload, ToolCall, ToolResult, ToolSpec, TurnResult, type XaiParams, anthropic, applyAnthropicCacheBreakpoints, arcee, baseten, cerebras, classifyOpenAICompatError, cursor, local, mapOAIFinishReason, openai, openaiCompat, openrouter, planBasetenReasoning, sanitizeToolSchema, sanitizeToolSpecs, xai };
package/dist/providers.js CHANGED
@@ -1,3 +1,11 @@
1
- import { C as sanitizeToolSchema, b as openaiCompat, g as OpenAICompatHttpError, v as classifyOpenAICompatError, w as sanitizeToolSpecs, y as mapOAIFinishReason } from "./messages-Iy_vEycX.js";
2
- import { a as local, d as planBasetenReasoning, f as arcee, i as openai, l as cerebras, m as applyAnthropicCacheBreakpoints, o as cursor, p as anthropic, r as openrouter, t as xai, u as baseten } from "./providers-BMw1D_lj.js";
1
+ import { f as mapOAIFinishReason, l as classifyOpenAICompatError, m as openaiCompat, n as OpenAICompatHttpError, v as sanitizeToolSchema, y as sanitizeToolSpecs } from "./openai-compat-0Y7jcncn.js";
2
+ import { n as applyAnthropicCacheBreakpoints, t as anthropic } from "./anthropic-RGqsJlC8.js";
3
+ import { arcee } from "./providers/arcee.js";
4
+ import { baseten, planBasetenReasoning } from "./providers/baseten.js";
5
+ import { cerebras } from "./providers/cerebras.js";
6
+ import { t as xai } from "./xai-tPdbAGkq.js";
7
+ import { t as cursor } from "./providers-DgmdYGKm.js";
8
+ import { local } from "./providers/local.js";
9
+ import { openai } from "./providers/openai.js";
10
+ import { openrouter } from "./providers/openrouter.js";
3
11
  export { OpenAICompatHttpError, anthropic, applyAnthropicCacheBreakpoints, arcee, baseten, cerebras, classifyOpenAICompatError, cursor, local, mapOAIFinishReason, openai, openaiCompat, openrouter, planBasetenReasoning, sanitizeToolSchema, sanitizeToolSpecs, xai };
package/dist/restate.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { K as SessionStore, Kn as ToolBatchExecutor, St as Provider, T as ToolDef, Tt as StreamOptions, Xn as ToolResultContent, cn as AgentBehavior, ln as AgentClock, o as McpToolMeta, s as McpToolWrap, w as ToolContext } from "./agent-DQIL5BFk.js";
1
+ import { K as SessionStore, Mn as AgentBehavior, Nn as AgentClock, Sr as ToolResultContent, St as Provider, T as ToolDef, Tt as StreamOptions, o as McpToolMeta, s as McpToolWrap, vr as ToolBatchExecutor, w as ToolContext } from "./agent-BAgOgS37.js";
2
2
  import { h as TaskExitInfo, l as ExecutionHandle, m as TaskEntry, o as DetachedTasksCapability } from "./types-Bs2oY7Ux.js";
3
3
 
4
4
  //#region src/restate/types.d.ts
@@ -0,0 +1,249 @@
1
+ import { Tt as StreamOptions, r as AgentHooks } from "./agent-BAgOgS37.js";
2
+ import { Hookable } from "hookable";
3
+
4
+ //#region src/cache-telemetry.d.ts
5
+ /**
6
+ * Snapshot of per-request dimensions that contribute to the provider-side
7
+ * prompt cache key. Hashed at `turn:before` and stashed for diffing on the
8
+ * next request.
9
+ *
10
+ * Hashes are FNV-1a 32-bit (cheap, no allocations on the hot path,
11
+ * collision rate good enough for diff detection — we're not signing
12
+ * anything). For verbose output the helper also captures byte lengths so
13
+ * `system: 1024 → 1031` reads like a real diff line.
14
+ */
15
+ interface CacheDimensionSnapshot {
16
+ /** Hash of `options.system` (with boundary marker preserved). */
17
+ systemHash: number;
18
+ /** Byte length of `options.system`. */
19
+ systemBytes: number;
20
+ /** Hash of the JSON-serialized `options.tools` array. */
21
+ toolsHash: number;
22
+ /** Number of tools in the array. */
23
+ toolsCount: number;
24
+ /** Model id. */
25
+ model: string;
26
+ /** Thinking level — `'off'` when absent. */
27
+ thinking: string;
28
+ /** Exact thinking budget — `0` when absent. */
29
+ thinkingBudget: number;
30
+ }
31
+ /** Result of {@link diffCacheDimensions}. */
32
+ interface CacheDimensionDiff {
33
+ /** Dimension names whose hashes differ between the two snapshots. */
34
+ changed: readonly CacheDimensionName[];
35
+ /** Per-dimension details — only filled for changed dimensions. */
36
+ details: Readonly<Partial<Record<CacheDimensionName, string>>>;
37
+ }
38
+ /** Cache-affecting dimension names. */
39
+ type CacheDimensionName = 'system' | 'tools' | 'model' | 'thinking' | 'thinkingBudget';
40
+ interface CacheBreakLoggerOptions {
41
+ /**
42
+ * Sink for log lines. Defaults to `console.error`. Use a {@link Logger} or
43
+ * a test buffer here when you want the output to land somewhere other than
44
+ * stderr.
45
+ */
46
+ log?: (line: string) => void;
47
+ /**
48
+ * When `true`, emit a log line on EVERY turn (not just cache breaks) with
49
+ * the per-dimension hashes. Useful for offline correlation; off by default
50
+ * to keep the logger zero-noise on happy paths.
51
+ */
52
+ verbose?: boolean;
53
+ /**
54
+ * Threshold for "this turn missed cache". The logger reports when
55
+ * `cacheRead < expectedReadAtLeast` AND the dimensions differ from the
56
+ * previous turn. Defaults to `1` — any cache read at all means the
57
+ * provider matched some prefix, so a strict "did we get any cache?" check
58
+ * is the right signal. Raise to detect partial-prefix breaks (e.g. the
59
+ * tools cache hit but the system prompt didn't, which lowers `cacheRead`
60
+ * without zeroing it).
61
+ */
62
+ expectedReadAtLeast?: number;
63
+ }
64
+ /**
65
+ * FNV-1a-style 32-bit hash over UTF-16 code units. Pure, allocation-free,
66
+ * ~10 ns per KB. Cryptographic strength is irrelevant here — we only need
67
+ * change detection, and this has effectively zero collision risk for the
68
+ * small number of dimensions tracked.
69
+ *
70
+ * Feeds the FULL char code into the mix (same as read-state's
71
+ * `hashContent`) — masking to the low byte would collapse code points that
72
+ * share a low byte, so a non-ASCII system-prompt change could hash
73
+ * identically and silently hide a cache-dimension drift.
74
+ *
75
+ * Exported for tests; callers shouldn't typically import directly.
76
+ */
77
+ declare function fnv1a32(s: string): number;
78
+ /**
79
+ * Build a {@link CacheDimensionSnapshot} from a `turn:before` payload.
80
+ *
81
+ * Pure — exported so hosts can compute snapshots outside the logger (e.g.
82
+ * stamping them onto custom telemetry spans). The hash is deterministic on
83
+ * byte-identical inputs.
84
+ */
85
+ declare function snapshotCacheDimensions(options: StreamOptions): CacheDimensionSnapshot;
86
+ /**
87
+ * Compare two snapshots and return the list of dimensions whose bytes
88
+ * differ. The `details` map carries a short human-readable description per
89
+ * changed dimension (e.g. `system: 1024 → 1031 bytes`).
90
+ *
91
+ * Pure / no I/O. Use this in tests to assert the diff logic; the logger
92
+ * itself just formats and emits the result.
93
+ */
94
+ declare function diffCacheDimensions(prev: CacheDimensionSnapshot, curr: CacheDimensionSnapshot): CacheDimensionDiff;
95
+ /**
96
+ * Install the cache-break logger on an agent's hook bus.
97
+ *
98
+ * Subscribes to `turn:before` (snapshot) + `turn:after` (compare with prior
99
+ * snapshot, log breaks). Returns an `uninstall` fn that detaches both
100
+ * listeners. Idempotent w.r.t. agent lifecycle — installs/uninstalls cleanly
101
+ * across runs.
102
+ *
103
+ * Recommended setup:
104
+ *
105
+ * ```ts
106
+ * const uninstall = installCacheBreakLogger(agent.hooks, {
107
+ * log: line => logger.debug(line),
108
+ * verbose: !!process.env.ZIDANE_DEBUG?.includes('cache'),
109
+ * })
110
+ * // ...
111
+ * uninstall()
112
+ * ```
113
+ *
114
+ * Performance: hashing runs on each `turn:before` and is bounded by the
115
+ * input size (system + tools serialization). Disabled callers pay nothing
116
+ * (don't install).
117
+ */
118
+ declare function installCacheBreakLogger(hooks: Hookable<AgentHooks>, options?: CacheBreakLoggerOptions): () => void;
119
+ //#endregion
120
+ //#region src/run-summary.d.ts
121
+ interface RunSummaryTokens {
122
+ input: number;
123
+ output: number;
124
+ cacheRead: number;
125
+ cacheCreation: number;
126
+ cost?: number;
127
+ /** First observable byte from the provider, ms from run start. */
128
+ ttftMs?: number;
129
+ }
130
+ interface RunSummaryByModel {
131
+ modelId: string;
132
+ input: number;
133
+ output: number;
134
+ cacheRead: number;
135
+ cacheCreation: number;
136
+ cost: number;
137
+ turns: number;
138
+ }
139
+ interface RunSummaryError {
140
+ kind: 'stream' | 'tool' | 'mcp-tool' | 'mcp' | 'spawn';
141
+ message: string;
142
+ errorType?: string;
143
+ turnId?: string;
144
+ callId?: string;
145
+ server?: string;
146
+ toolName?: string;
147
+ childId?: string;
148
+ statusCode?: number;
149
+ requestId?: string;
150
+ }
151
+ interface RunSummaryBlock {
152
+ callId: string;
153
+ toolName: string;
154
+ outcome: 'gate-block' | 'unknown' | 'invalid-input';
155
+ reason?: string;
156
+ }
157
+ interface RunSummaryValidation {
158
+ callId: string;
159
+ toolName: string;
160
+ reason: string;
161
+ }
162
+ interface RunSummaryBudget {
163
+ kind: 'bytes' | 'tool-count';
164
+ /** Tool name (for `'tool-count'`); absent for byte budgets. */
165
+ toolName?: string;
166
+ /** `mode` for `'tool-count'`; absent for byte budgets. */
167
+ mode?: 'steer' | 'block';
168
+ observed: number;
169
+ limit: number;
170
+ turnId?: string;
171
+ }
172
+ interface RunSummaryRepeatGuard {
173
+ toolName: string;
174
+ /** Observed repeat count that tripped the guard. */
175
+ count: number;
176
+ threshold: number;
177
+ action: 'block' | 'steer' | 'abort';
178
+ turnId?: string;
179
+ }
180
+ /**
181
+ * Postmortem snapshot of one `agent.run()`. Strictly serializable — every
182
+ * field round-trips through `JSON.stringify` / `JSON.parse` without loss
183
+ * so a log aggregator can ingest it as-is.
184
+ */
185
+ interface RunSummary {
186
+ runId?: string;
187
+ parentRunId?: string;
188
+ depth: number;
189
+ agentName?: string;
190
+ startedAt: number;
191
+ endedAt: number;
192
+ durationMs: number;
193
+ status: 'completed' | 'aborted';
194
+ turns: number;
195
+ totals: RunSummaryTokens;
196
+ byModel: RunSummaryByModel[];
197
+ errors: RunSummaryError[];
198
+ blocks: RunSummaryBlock[];
199
+ validationRejects: RunSummaryValidation[];
200
+ budgetEvents: RunSummaryBudget[];
201
+ /**
202
+ * Repeat-guard escalations. An `action: 'steer'` entry means the tool still
203
+ * executed and got a steering message appended to its result. An
204
+ * `action: 'abort'` entry means the guard terminated the run via the agent's
205
+ * AbortController (the run finalizes as `'aborted'`).
206
+ */
207
+ repeatGuardEvents: RunSummaryRepeatGuard[];
208
+ /** Counts of pairing repairs, keyed by repair mode. */
209
+ pairingRepairs: Record<string, number>;
210
+ /**
211
+ * Postmortem snapshots of child runs that bubbled their stats up via
212
+ * `spawn:complete`. Only present when the run actually spawned.
213
+ */
214
+ children?: RunSummary[];
215
+ }
216
+ interface RunSummaryCollectorOptions {
217
+ /**
218
+ * Called with the assembled {@link RunSummary} on every `agent:done`.
219
+ * Synchronous — heavy I/O should be deferred (e.g. via `setImmediate`).
220
+ */
221
+ onSummary?: (summary: RunSummary) => void;
222
+ }
223
+ interface RunSummaryCollector {
224
+ /** Install the collector's hook handlers. Returns an uninstall fn. */
225
+ install: (hooks: Hookable<AgentHooks>) => () => void;
226
+ /** Most-recent summary; `undefined` until the first `agent:done` fires. */
227
+ latest: () => RunSummary | undefined;
228
+ }
229
+ /**
230
+ * Build a run-summary collector. State is created fresh inside each
231
+ * `install()` call, so a single collector instance can be installed
232
+ * across multiple agents without attribution cross-talk. `latest()`
233
+ * returns the most-recent summary across **any** install — install
234
+ * per-agent collectors if you need separate post-run snapshots.
235
+ *
236
+ * @example
237
+ * ```ts
238
+ * const collector = createRunSummaryCollector({
239
+ * onSummary: s => console.log(JSON.stringify(s)),
240
+ * })
241
+ * const uninstall = collector.install(agent.hooks)
242
+ * try { await agent.run({ prompt }) }
243
+ * finally { uninstall() }
244
+ * ```
245
+ */
246
+ declare function createRunSummaryCollector(options?: RunSummaryCollectorOptions): RunSummaryCollector;
247
+ //#endregion
248
+ export { fnv1a32 as _, RunSummaryCollector as a, RunSummaryRepeatGuard as c, createRunSummaryCollector as d, CacheBreakLoggerOptions as f, diffCacheDimensions as g, CacheDimensionSnapshot as h, RunSummaryByModel as i, RunSummaryTokens as l, CacheDimensionName as m, RunSummaryBlock as n, RunSummaryCollectorOptions as o, CacheDimensionDiff as p, RunSummaryBudget as r, RunSummaryError as s, RunSummary as t, RunSummaryValidation as u, installCacheBreakLogger as v, snapshotCacheDimensions as y };
249
+ //# sourceMappingURL=run-summary-DAnBZnrt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"run-summary-DAnBZnrt.d.ts","names":[],"sources":["../src/cache-telemetry.ts","../src/run-summary.ts"],"mappings":";;;;AA8EA;;;;AAA8B;AAW9B;;;;;AAXA,UA1BiB,sBAAA;EAiDf;EA/CA,UAAA;EAyDmB;EAvDnB,WAAA;EA8Ec;EA5Ed,SAAA;;EAEA,UAAA;EA0E+B;EAxE/B,KAAA;EA2FqC;EAzFrC,QAAA;EAyFqF;EAvFrF,cAAA;AAAA;;UAIe,kBAAA;EAmFsE;EAjFrF,OAAA,WAAkB,kBAAA;EA0Ge;EAxGjC,OAAA,EAAS,QAAA,CAAS,OAAA,CAAQ,MAAA,CAAO,kBAAA;AAAA;;KAIvB,kBAAA;AAAA,UAWK,uBAAA;EA4FI;;;;;EAtFnB,GAAA,IAAO,IAAA;EAsFY;AAAA;AA2DrB;;;EA3IE,OAAA;EA4IO;;;;;;;;;EAlIP,mBAAA;AAAA;;;;AC7EF;;;;;;;;;;iBDoGgB,OAAA,CAAQ,CAAS;AC7FzB;AAGR;;;;;;AAHQ,iBDgHQ,uBAAA,CAAwB,OAAA,EAAS,aAAA,GAAgB,sBAAsB;;;;;;ACtGhF;AAGP;;iBD4HgB,mBAAA,CACd,IAAA,EAAM,sBAAA,EACN,IAAA,EAAM,sBAAA,GACL,kBAAA;;;;;;;;;;;;;ACrHQ;AAGX;;;;;;;;;AAIQ;iBDyKQ,uBAAA,CACd,KAAA,EAAO,QAAA,CAAS,UAAA,GAChB,OAAA,GAAS,uBAAA;;;UChNM,gBAAA;EACf,KAAA;EACA,MAAA;EACA,SAAA;EACA,aAAA;EACA,IAAA;EDmC0B;ECjC1B,MAAA;AAAA;AAAA,UAGe,iBAAA;EACf,OAAA;EACA,KAAA;EACA,MAAA;EACA,SAAA;EACA,aAAA;EACA,IAAA;EACA,KAAA;AAAA;AAAA,UAGe,eAAA;EACf,IAAA;EACA,OAAA;EACA,SAAA;EACA,MAAA;EACA,MAAA;EACA,MAAA;EACA,QAAA;EACA,OAAA;EACA,UAAA;EACA,SAAA;AAAA;AAAA,UAGe,eAAA;EACf,MAAA;EACA,QAAA;EACA,OAAA;EACA,MAAA;AAAA;AAAA,UAGe,oBAAA;EACf,MAAA;EACA,QAAA;EACA,MAAA;AAAA;AAAA,UAGe,gBAAA;EACf,IAAA;EDmGM;ECjGN,QAAA;EDkGmB;EChGnB,IAAA;EACA,QAAA;EACA,KAAA;EACA,MAAA;AAAA;AAAA,UAGe,qBAAA;EACf,QAAA;EDyFmB;ECvFnB,KAAA;EACA,SAAA;EACA,MAAA;EACA,MAAA;AAAA;;;;;;UAQe,UAAA;EACf,KAAA;EACA,WAAA;EACA,KAAA;EACA,SAAA;EACA,SAAA;EACA,OAAA;EACA,UAAA;EACA,MAAA;EACA,KAAA;EACA,MAAA,EAAQ,gBAAA;EACR,OAAA,EAAS,iBAAA;EACT,MAAA,EAAQ,eAAA;EACR,MAAA,EAAQ,eAAA;EACR,iBAAA,EAAmB,oBAAA;EACnB,YAAA,EAAc,gBAAA;EAjFd;;;AAEM;AAGR;;EAmFE,iBAAA,EAAmB,qBAAA;EAnFa;EAqFhC,cAAA,EAAgB,MAAA;EAnFhB;;;;EAwFA,QAAA,GAAW,UAAA;AAAA;AAAA,UAOI,0BAAA;EA1FV;AAGP;;;EA4FE,SAAA,IAAa,OAAA,EAAS,UAAU;AAAA;AAAA,UAGjB,mBAAA;EA5Ff;EA8FA,OAAA,GAAU,KAAA,EAAO,QAAA,CAAS,UAAA;EA5F1B;EA8FA,MAAA,QAAc,UAAA;AAAA;;;;;AAzFL;AAGX;;;;;;;;;AAIQ;AAGR;;iBAmGgB,yBAAA,CACd,OAAA,GAAS,0BAAA,GACR,mBAAmB"}