@jini-ai/chat 0.6.15-rc.2 → 0.6.16

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 (126) hide show
  1. package/README.md +6 -1
  2. package/dist/core/accepted-input.js +20 -11
  3. package/dist/core/ag-ui/entry.js +3 -1
  4. package/dist/core/agent-plugin-chat-state.js +3 -1
  5. package/dist/core/antigravity/tool-presentation.d.ts +13 -0
  6. package/dist/core/antigravity/tool-presentation.js +20 -0
  7. package/dist/core/assistant-client/ag-ui-transport.js +14 -2
  8. package/dist/core/assistant-client/attachment-liveness.js +1 -1
  9. package/dist/core/assistant-client/durable-run-subscription.js +2 -1
  10. package/dist/core/assistant-client/transport.js +13 -7
  11. package/dist/core/assistant-content.js +2 -1
  12. package/dist/core/composer-history.js +2 -1
  13. package/dist/core/durable-projection.js +2 -1
  14. package/dist/core/durable-runs/continuation.js +2 -1
  15. package/dist/core/events.d.ts +5 -1
  16. package/dist/core/messages.d.ts +5 -1
  17. package/dist/core/partial-json.js +18 -9
  18. package/dist/core/persistence/title.d.ts +1 -1
  19. package/dist/core/persistence/title.js +25 -7
  20. package/dist/core/question-form/normalize.js +1 -1
  21. package/dist/core/question-form/scan.js +25 -15
  22. package/dist/core/question-form/secret-answers.js +2 -1
  23. package/dist/core/run-activity.js +8 -4
  24. package/dist/core/run-events/entry.js +6 -2
  25. package/dist/core/tool-events.d.ts +18 -8
  26. package/dist/core/tool-events.js +72 -16
  27. package/dist/core/tool-presentation.d.ts +14 -0
  28. package/dist/core/tool-presentation.js +8 -0
  29. package/dist/core/transcript.js +13 -6
  30. package/dist/core/turn-usage.js +7 -2
  31. package/dist/core/user-text-redaction.d.ts +4 -6
  32. package/dist/core/user-text-redaction.js +13 -6
  33. package/dist/core/util/manifest.js +13 -11
  34. package/dist/core/util/markdown-context.d.ts +14 -0
  35. package/dist/core/util/markdown-context.js +42 -4
  36. package/dist/core/util/markup-attributes.js +1 -1
  37. package/dist/core/util/parser.js +7 -7
  38. package/dist/core/util/pointer.js +22 -6
  39. package/dist/core/util/recover.js +5 -8
  40. package/dist/core/util/strip.js +12 -15
  41. package/dist/core/util/validate.js +30 -18
  42. package/dist/embed-widget/browser/frontend-session-bridge.d.ts +99 -0
  43. package/dist/embed-widget/browser/frontend-session-bridge.js +384 -0
  44. package/dist/embed-widget/browser/lazy-loader.js +16 -12
  45. package/dist/embed-widget/browser/session-store.d.ts +3 -9
  46. package/dist/embed-widget/browser/session-store.js +6 -38
  47. package/dist/embed-widget/react/dialog.hooks.js +2 -2
  48. package/dist/embed-widget/react/embed.d.ts +3 -10
  49. package/dist/embed-widget/react/embed.js +8 -52
  50. package/dist/embed-widget/react/header.hooks.js +1 -1
  51. package/dist/embed-widget/transports/fetch-sse.js +2 -1
  52. package/dist/embed-widget/vanilla/index.d.ts +0 -5
  53. package/dist/embed-widget/vanilla/index.js +23 -26
  54. package/dist/embed-widget/vanilla/state.d.ts +3 -11
  55. package/dist/embed-widget/vanilla/state.js +10 -39
  56. package/dist/embed-widget/vanilla/style.css +1 -1
  57. package/dist/react/agent-bridge/frontend-session-bridge.d.ts +2 -56
  58. package/dist/react/agent-bridge/frontend-session-bridge.js +2 -248
  59. package/dist/react/components/AttachmentPreviewModal.hooks.js +2 -1
  60. package/dist/react/components/ChatSettingsDialog.js +18 -9
  61. package/dist/react/components/Composer.js +5 -4
  62. package/dist/react/components/ConversationList.js +5 -4
  63. package/dist/react/components/Icon.d.ts +1 -1
  64. package/dist/react/components/Icon.js +1 -0
  65. package/dist/react/components/Markdown.d.ts +1 -0
  66. package/dist/react/components/Markdown.js +30 -27
  67. package/dist/react/components/McpUiSurfaceCard.js +2 -1
  68. package/dist/react/components/MessageList.d.ts +1 -1
  69. package/dist/react/components/MessageList.hooks.js +3 -2
  70. package/dist/react/components/MessageRow.d.ts +3 -0
  71. package/dist/react/components/MessageRow.js +32 -14
  72. package/dist/react/components/MessageRow.usage.js +3 -1
  73. package/dist/react/components/QuestionForm.js +4 -5
  74. package/dist/react/components/SentAttachment.js +4 -1
  75. package/dist/react/components/TodoCard.js +9 -1
  76. package/dist/react/components/ToolCard.d.ts +3 -1
  77. package/dist/react/components/ToolCard.js +84 -64
  78. package/dist/react/components/ToolCard.rules.d.ts +20 -0
  79. package/dist/react/components/ToolCard.rules.js +92 -0
  80. package/dist/react/components/composer-discovery.js +8 -8
  81. package/dist/react/features/chat-pane/components/AgentPluginUsage.js +1 -2
  82. package/dist/react/features/chat-pane/components/AgentRuntimePicker.d.ts +1 -1
  83. package/dist/react/features/chat-pane/components/AgentRuntimePicker.js +31 -9
  84. package/dist/react/features/chat-pane/components/ChatPane.js +7 -5
  85. package/dist/react/features/chat-pane/components/RuntimeDropUp.js +1 -1
  86. package/dist/react/features/chat-pane/create-daemon-attachment-uploader.js +1 -1
  87. package/dist/react/features/chat-pane/hooks/useAgentRuntimePicker.hooks.js +2 -2
  88. package/dist/react/features/chat-pane/hooks/useChatPane.hooks.d.ts +3 -1
  89. package/dist/react/features/chat-pane/hooks/useChatPane.hooks.js +13 -5
  90. package/dist/react/features/chat-pane/hooks/useChatPaneAgentControl.hooks.js +2 -2
  91. package/dist/react/features/chat-pane/hooks/useChatPaneControlsHeight.hooks.js +1 -1
  92. package/dist/react/features/chat-pane/hooks/useChatPaneRuntimeInventory.hooks.js +2 -2
  93. package/dist/react/features/chat-pane/hooks/useChatPaneWorkingDirectory.hooks.js +2 -2
  94. package/dist/react/features/chat-pane/hooks/useRuntimeDropUp.hooks.js +2 -2
  95. package/dist/react/features/chat-pane/model-options.js +4 -2
  96. package/dist/react/features/chat-pane/styles.d.ts +1 -1
  97. package/dist/react/features/chat-pane/styles.js +95 -5
  98. package/dist/react/features/chat-pane/types.d.ts +11 -0
  99. package/dist/react/hooks/assistant-chats.js +22 -8
  100. package/dist/react/hooks/useArtifactStream.js +2 -1
  101. package/dist/react/hooks/useComposer.js +2 -2
  102. package/dist/react/hooks/useComposerHistoryKeys.hooks.js +2 -2
  103. package/dist/react/hooks/useConversation.js +9 -4
  104. package/dist/react/hooks/useExtEventGroups.js +4 -2
  105. package/dist/react/hooks/useLatestOperation.js +2 -1
  106. package/dist/react/hooks/useQuestionForms.js +32 -22
  107. package/dist/react/hooks/useRunStream.js +4 -2
  108. package/dist/react/hooks/useUserTextGuard.d.ts +1 -0
  109. package/dist/react/hooks/useUserTextGuard.js +3 -1
  110. package/dist/react/message-blocks.js +4 -2
  111. package/dist/react/styles/reference.css +9 -0
  112. package/dist/react/tool-call-display.d.ts +11 -0
  113. package/dist/react/tool-call-display.js +59 -2
  114. package/dist/server/durable-runs/recover.js +13 -5
  115. package/dist/server/run-finalizer/entry.js +1 -0
  116. package/dist/store/runtime/chat-history-store.js +9 -3
  117. package/dist/store/runtime/durable-run-store.js +34 -24
  118. package/dist/store/runtime/run-ledger.js +7 -4
  119. package/dist/store/sql/boundary.js +3 -1
  120. package/dist/store/sql/cursor.js +8 -3
  121. package/dist/store/sql/store.js +36 -28
  122. package/package.json +93 -88
  123. package/dist/core/browser/page-actions.d.ts +0 -121
  124. package/dist/core/browser/page-actions.js +0 -115
  125. package/dist/embed-widget/browser/page-actions.d.ts +0 -2
  126. package/dist/embed-widget/browser/page-actions.js +0 -3
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jini-ai/chat",
3
- "version": "0.6.15-rc.2",
3
+ "version": "0.6.16",
4
4
  "description": "Jini's chat/artifact frontend, consolidated into one package with two subpaths: framework-free chat vocabulary and pure parsers in `/core`, headless hooks + presentational components + slots in `/react`. Import only the layer you need.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {
@@ -33,22 +33,39 @@
33
33
  "./transports/http": "universal",
34
34
  "./transports/ag-ui": "universal",
35
35
  "./browser/session-store": "browser",
36
- "./browser/page-actions": "browser",
37
36
  "./server/durable-runs": "node",
38
37
  "./store/runtime": "node",
39
38
  "./vanilla": "browser",
40
39
  "./browser/lazy-loader": "browser",
41
- "./vanilla/style.css": "browser"
40
+ "./vanilla/style.css": "browser",
41
+ "./browser/frontend-session-bridge": "browser"
42
42
  },
43
43
  "neutralEntries": [
44
44
  "src/store/contracts"
45
45
  ],
46
46
  "isolation": {
47
47
  "entries": {
48
- "./browser/page-actions": "core",
49
48
  "./transports/http": "core",
50
- "./transports/ag-ui": "core"
49
+ "./transports/ag-ui": "core",
50
+ "./browser/frontend-session-bridge": "core"
51
51
  }
52
+ },
53
+ "optionalPeers": {
54
+ "better-sqlite3": "opt-in: sqlite storage — SQLite storage could not load better-sqlite3. Install better-sqlite3 to enable this feature, or check its installed version and native binaries.",
55
+ "@electric-sql/pglite": "opt-in: embedded postgresql storage — Embedded PostgreSQL storage could not load @electric-sql/pglite. Install @electric-sql/pglite to enable this feature, or check its installed version and native binaries.",
56
+ "pg": "opt-in: postgresql storage — PostgreSQL storage could not load pg. Install pg to enable this feature, or check its installed version and native binaries.",
57
+ "@ag-ui/core": "opt-in: ag ui protocol adapter; import @jini-ai/chat/core/ag-ui — AG UI protocol adapter could not load @ag-ui/core. Install @ag-ui/core to enable this feature, or check its installed version and native binaries.",
58
+ "@mcp-ui/client": "opt-in: mcp ui renderer; import @jini-ai/chat/react — MCP UI renderer could not load @mcp-ui/client. Install @mcp-ui/client to enable this feature, or check its installed version and native binaries.",
59
+ "@radix-ui/react-checkbox": "opt-in: interactive ui controls; import @jini-ai/chat/react — Interactive UI controls could not load @radix-ui/react-checkbox. Install @radix-ui/react-checkbox to enable this feature, or check its installed version and native binaries.",
60
+ "@radix-ui/react-label": "opt-in: interactive ui controls; import @jini-ai/chat/react — Interactive UI controls could not load @radix-ui/react-label. Install @radix-ui/react-label to enable this feature, or check its installed version and native binaries.",
61
+ "@radix-ui/react-radio-group": "opt-in: interactive ui controls; import @jini-ai/chat/react — Interactive UI controls could not load @radix-ui/react-radio-group. Install @radix-ui/react-radio-group to enable this feature, or check its installed version and native binaries.",
62
+ "@radix-ui/react-select": "opt-in: interactive ui controls; import @jini-ai/chat/react — Interactive UI controls could not load @radix-ui/react-select. Install @radix-ui/react-select to enable this feature, or check its installed version and native binaries.",
63
+ "@radix-ui/react-slot": "opt-in: interactive ui controls — Interactive UI controls could not load @radix-ui/react-slot. Install @radix-ui/react-slot to enable this feature, or check its installed version and native binaries.",
64
+ "@jini-ai/agent-runtime": "opt-in: agent execution adapters; import @jini-ai/chat/react — Agent execution adapters could not load @jini-ai/agent-runtime. Install @jini-ai/agent-runtime to enable this feature, or check its installed version and native binaries.",
65
+ "@jini-ai/protocol": "opt-in: agent protocol adapters; import @jini-ai/chat/server/durable-runs — Agent protocol adapters could not load @jini-ai/protocol. Install @jini-ai/protocol to enable this feature, or check its installed version and native binaries.",
66
+ "@jini-ai/ui": "opt-in: ui integrations; import @jini-ai/chat/react — UI integrations could not load @jini-ai/ui. Install @jini-ai/ui to enable this feature, or check its installed version and native binaries.",
67
+ "react": "opt-in: react chat ui; import @jini-ai/chat/react — React chat UI could not load react. Install react to enable this feature, or check its installed version.",
68
+ "react-dom": "opt-in: react chat ui; import @jini-ai/chat/react — React chat UI could not load react-dom. Install react-dom to enable this feature, or check its installed version."
52
69
  }
53
70
  },
54
71
  "type": "module",
@@ -150,11 +167,6 @@
150
167
  "import": "./dist/embed-widget/browser/session-store.js",
151
168
  "default": "./dist/embed-widget/browser/session-store.js"
152
169
  },
153
- "./browser/page-actions": {
154
- "types": "./dist/embed-widget/browser/page-actions.d.ts",
155
- "import": "./dist/embed-widget/browser/page-actions.js",
156
- "default": "./dist/embed-widget/browser/page-actions.js"
157
- },
158
170
  "./server/durable-runs": {
159
171
  "types": "./dist/server/durable-runs/entry.d.ts",
160
172
  "import": "./dist/server/durable-runs/entry.js",
@@ -175,7 +187,12 @@
175
187
  "import": "./dist/embed-widget/browser/lazy-loader.js",
176
188
  "default": "./dist/embed-widget/browser/lazy-loader.js"
177
189
  },
178
- "./vanilla/style.css": "./dist/embed-widget/vanilla/style.css"
190
+ "./vanilla/style.css": "./dist/embed-widget/vanilla/style.css",
191
+ "./browser/frontend-session-bridge": {
192
+ "types": "./dist/embed-widget/browser/frontend-session-bridge.d.ts",
193
+ "import": "./dist/embed-widget/browser/frontend-session-bridge.js",
194
+ "default": "./dist/embed-widget/browser/frontend-session-bridge.js"
195
+ }
179
196
  },
180
197
  "files": [
181
198
  "dist",
@@ -196,13 +213,15 @@
196
213
  "registry": "https://registry.npmjs.org"
197
214
  },
198
215
  "dependencies": {
199
- "@jini-ai/core": "^0.6.15-rc.2"
216
+ "kysely": "^0.29.6",
217
+ "@jini-ai/core": "^0.6.16",
218
+ "@jini-ai/diagnostics": "^0.6.16",
219
+ "@jini-ai/db": "^0.6.16",
220
+ "@jini-ai/agentic": "^0.6.16"
200
221
  },
201
222
  "peerDependencies": {
202
223
  "react": "^18.3.0 || ^19.0.0",
203
224
  "react-dom": "^18.3.0 || ^19.0.0",
204
- "@jini-ai/db": "^0.6.15-rc.2",
205
- "kysely": "^0.29.6",
206
225
  "better-sqlite3": "^13.0.0",
207
226
  "@electric-sql/pglite": "0.5.8",
208
227
  "pg": "^8.23.0",
@@ -213,70 +232,9 @@
213
232
  "@radix-ui/react-radio-group": "^1.4.7",
214
233
  "@radix-ui/react-select": "^2.3.7",
215
234
  "@radix-ui/react-slot": "^1.3.3",
216
- "@jini-ai/agent-runtime": "^0.6.15-rc.2",
217
- "@jini-ai/agentic": "^0.6.15-rc.2",
218
- "@jini-ai/protocol": "^0.6.15-rc.2",
219
- "@jini-ai/ui": "^0.6.15-rc.2",
220
- "@jini-ai/diagnostics": "^0.6.15-rc.2"
221
- },
222
- "peerDependenciesMeta": {
223
- "react": {
224
- "optional": true
225
- },
226
- "react-dom": {
227
- "optional": true
228
- },
229
- "@jini-ai/db": {
230
- "optional": true
231
- },
232
- "kysely": {
233
- "optional": true
234
- },
235
- "better-sqlite3": {
236
- "optional": true
237
- },
238
- "@electric-sql/pglite": {
239
- "optional": true
240
- },
241
- "pg": {
242
- "optional": true
243
- },
244
- "@ag-ui/core": {
245
- "optional": true
246
- },
247
- "@mcp-ui/client": {
248
- "optional": true
249
- },
250
- "@radix-ui/react-checkbox": {
251
- "optional": true
252
- },
253
- "@radix-ui/react-label": {
254
- "optional": true
255
- },
256
- "@radix-ui/react-radio-group": {
257
- "optional": true
258
- },
259
- "@radix-ui/react-select": {
260
- "optional": true
261
- },
262
- "@radix-ui/react-slot": {
263
- "optional": true
264
- },
265
- "@jini-ai/agent-runtime": {
266
- "optional": true
267
- },
268
- "@jini-ai/agentic": {
269
- "optional": true
270
- },
271
- "@jini-ai/protocol": {
272
- "optional": true
273
- },
274
- "@jini-ai/ui": {
275
- "optional": true
276
- },
277
- "@jini-ai/diagnostics": {
278
- "optional": true
279
- }
235
+ "@jini-ai/agent-runtime": "^0.6.10",
236
+ "@jini-ai/protocol": "^0.6.10",
237
+ "@jini-ai/ui": "^0.6.10"
280
238
  },
281
239
  "devDependencies": {
282
240
  "@mcp-ui/client": "7.1.1",
@@ -303,13 +261,13 @@
303
261
  "pg": "8.23.0",
304
262
  "@ag-ui/core": "0.0.58",
305
263
  "fast-check": "4.3.0",
306
- "@jini-ai/db": "0.6.15-rc.2",
307
- "@jini-ai/agentic": "^0.6.15-rc.2",
308
- "@jini-ai/agent-runtime": "0.6.15-rc.2",
309
- "@jini-ai/ui": "^0.6.15-rc.2",
310
- "@jini-ai/core": "^0.6.15-rc.2",
311
- "@jini-ai/protocol": "^0.6.15-rc.2",
312
- "@jini-ai/diagnostics": "^0.6.15-rc.2"
264
+ "@jini-ai/agent-runtime": "0.6.16",
265
+ "@jini-ai/db": "0.6.16",
266
+ "@jini-ai/agentic": "^0.6.16",
267
+ "@jini-ai/diagnostics": "^0.6.16",
268
+ "@jini-ai/core": "^0.6.16",
269
+ "@jini-ai/protocol": "^0.6.16",
270
+ "@jini-ai/ui": "^0.6.16"
313
271
  },
314
272
  "typesVersions": {
315
273
  "*": {
@@ -361,9 +319,6 @@
361
319
  "browser/session-store": [
362
320
  "./dist/embed-widget/browser/session-store.d.ts"
363
321
  ],
364
- "browser/page-actions": [
365
- "./dist/embed-widget/browser/page-actions.d.ts"
366
- ],
367
322
  "server/durable-runs": [
368
323
  "./dist/server/durable-runs/entry.d.ts"
369
324
  ],
@@ -375,9 +330,59 @@
375
330
  ],
376
331
  "browser/lazy-loader": [
377
332
  "./dist/embed-widget/browser/lazy-loader.d.ts"
333
+ ],
334
+ "browser/frontend-session-bridge": [
335
+ "./dist/embed-widget/browser/frontend-session-bridge.d.ts"
378
336
  ]
379
337
  }
380
338
  },
339
+ "peerDependenciesMeta": {
340
+ "better-sqlite3": {
341
+ "optional": true
342
+ },
343
+ "@electric-sql/pglite": {
344
+ "optional": true
345
+ },
346
+ "pg": {
347
+ "optional": true
348
+ },
349
+ "@ag-ui/core": {
350
+ "optional": true
351
+ },
352
+ "@mcp-ui/client": {
353
+ "optional": true
354
+ },
355
+ "@radix-ui/react-checkbox": {
356
+ "optional": true
357
+ },
358
+ "@radix-ui/react-label": {
359
+ "optional": true
360
+ },
361
+ "@radix-ui/react-radio-group": {
362
+ "optional": true
363
+ },
364
+ "@radix-ui/react-select": {
365
+ "optional": true
366
+ },
367
+ "@radix-ui/react-slot": {
368
+ "optional": true
369
+ },
370
+ "@jini-ai/agent-runtime": {
371
+ "optional": true
372
+ },
373
+ "@jini-ai/protocol": {
374
+ "optional": true
375
+ },
376
+ "@jini-ai/ui": {
377
+ "optional": true
378
+ },
379
+ "react": {
380
+ "optional": true
381
+ },
382
+ "react-dom": {
383
+ "optional": true
384
+ }
385
+ },
381
386
  "scripts": {
382
387
  "build": "tsc -p tsconfig.json && mkdir -p dist/react/styles && cp src/react/styles/reference.css dist/react/styles/ && mkdir -p dist/embed-widget/vanilla && node --input-type=module -e \"import {writeFileSync,readFileSync} from 'node:fs'; import {CHAT_BUBBLE_STYLE} from './dist/embed-widget/browser/lazy-loader.js'; writeFileSync('dist/embed-widget/vanilla/style.css',CHAT_BUBBLE_STYLE+'\\n'+readFileSync('src/embed-widget/vanilla/style.css','utf8'));\"",
383
388
  "typecheck": "tsc -p tsconfig.json --noEmit",
@@ -1,121 +0,0 @@
1
- /** Resolved target supplied by the host; the client never derives a path from a title. */
2
- export interface ResolvedPageTarget {
3
- readonly slug: string;
4
- readonly title: string;
5
- readonly path: string;
6
- }
7
- export type PageAction = {
8
- readonly type: 'navigate';
9
- readonly target: ResolvedPageTarget;
10
- readonly auto: boolean;
11
- } | {
12
- readonly type: 'scroll_to' | 'highlight';
13
- readonly target: ResolvedPageTarget;
14
- };
15
- export type NavigateAction = Extract<PageAction, {
16
- type: 'navigate';
17
- }>;
18
- export type NonNavigateAction = Exclude<PageAction, {
19
- type: 'navigate';
20
- }>;
21
- export interface DirectiveCarryingEvent {
22
- readonly kind: string;
23
- readonly name?: string;
24
- readonly data?: unknown;
25
- }
26
- export interface SplitPageActions {
27
- readonly navigate: NavigateAction | null;
28
- readonly other: NonNavigateAction | null;
29
- }
30
- /** Narrows an untrusted, bare queued action. URL authorization remains a separate host policy. O(1). */
31
- export declare function isQueuedPageAction(args: {
32
- value: unknown;
33
- }): args is {
34
- value: PageAction;
35
- };
36
- /** Narrows an untrusted directive envelope, dropping unknown kinds. O(1). */
37
- export declare function isPageActionDirective(args: {
38
- value: unknown;
39
- }): args is {
40
- value: {
41
- kind: 'page_action';
42
- action: PageAction;
43
- };
44
- };
45
- /** Preserves valid action order while ignoring unrelated events. O(events) time and output space. */
46
- export declare function extractPageActions({ events, directiveEventName }: {
47
- events: readonly DirectiveCarryingEvent[] | undefined;
48
- directiveEventName: string;
49
- }): PageAction[];
50
- /** Returns only the first navigation and first page treatment. O(actions), O(1) extra space. */
51
- export declare function splitPageActions({ actions }: {
52
- actions: readonly PageAction[];
53
- }): SplitPageActions;
54
- export interface TargetSelectionPolicy {
55
- readonly candidateSelector: string;
56
- readonly excludedAncestorSelector: string;
57
- }
58
- /** Exact title match first, case-insensitive fallback; never searches excluded UI. O(candidates). */
59
- export declare function findTargetElement({ title, root, selection }: {
60
- title: string;
61
- root: Pick<ParentNode, 'querySelectorAll'>;
62
- selection: TargetSelectionPolicy;
63
- }): Element | null;
64
- export interface PageActionTimerPort {
65
- schedule(args: {
66
- callback: () => void;
67
- delayMs: number;
68
- }): unknown;
69
- cancel(args: {
70
- handle: unknown;
71
- }): void;
72
- }
73
- export interface PageActionPort {
74
- allows(args: {
75
- action: PageAction;
76
- }): boolean;
77
- navigate(args: {
78
- action: NavigateAction;
79
- }): boolean;
80
- execute(args: {
81
- action: NonNavigateAction;
82
- }): boolean;
83
- clearHighlight(args: Record<string, never>): void;
84
- }
85
- export interface BrowserPageActionController extends PageActionPort {
86
- applyHighlight(args: {
87
- element: Element;
88
- }): void;
89
- scrollToElement(args: {
90
- element: Element;
91
- }): void;
92
- }
93
- export interface BrowserPageActionsArgs {
94
- readonly root: Pick<ParentNode, 'querySelectorAll'>;
95
- readonly selection: TargetSelectionPolicy;
96
- readonly allowPath: (args: {
97
- path: string;
98
- }) => boolean;
99
- readonly navigate: (args: {
100
- path: string;
101
- }) => void;
102
- readonly reducedMotion: (args: Record<string, never>) => boolean;
103
- readonly scroll: (args: {
104
- element: Element;
105
- options: ScrollIntoViewOptions;
106
- }) => void;
107
- readonly timers: PageActionTimerPort;
108
- readonly highlightClass: string;
109
- readonly fadeAnimationName: string;
110
- readonly cleanupFallbackMs: number;
111
- }
112
- /**
113
- * Creates page effects with injected DOM, navigation, URL policy, scroll and timers.
114
- * At most one highlight belongs to this instance; cleanup and navigation remove it.
115
- * URL policy is checked before queueing, navigation or page effects. Stale timers and descendant
116
- * animation events cannot remove the current highlight. Navigation paths are resolved by the host,
117
- * never guessed from a title; each controller owns its mutable highlight state.
118
- * @complexity Execute O(candidates); other operations O(1), with one timer/listener retained.
119
- */
120
- export declare function createBrowserPageActions(args: BrowserPageActionsArgs): BrowserPageActionController;
121
- //# sourceMappingURL=page-actions.d.ts.map
@@ -1,115 +0,0 @@
1
- function record(value) {
2
- return typeof value === 'object' && value !== null && !Array.isArray(value);
3
- }
4
- function target(value) {
5
- return record(value) && typeof value.slug === 'string' && typeof value.title === 'string' && typeof value.path === 'string';
6
- }
7
- /** Narrows an untrusted, bare queued action. URL authorization remains a separate host policy. O(1). */
8
- export function isQueuedPageAction(args) {
9
- const { value } = args;
10
- if (!record(value) || !target(value.target))
11
- return false;
12
- return value.type === 'navigate' ? typeof value.auto === 'boolean' : value.type === 'scroll_to' || value.type === 'highlight';
13
- }
14
- /** Narrows an untrusted directive envelope, dropping unknown kinds. O(1). */
15
- export function isPageActionDirective(args) {
16
- const { value } = args;
17
- return record(value) && value.kind === 'page_action' && isQueuedPageAction({ value: value.action });
18
- }
19
- /** Preserves valid action order while ignoring unrelated events. O(events) time and output space. */
20
- export function extractPageActions({ events, directiveEventName }) {
21
- const actions = [];
22
- for (const event of events ?? []) {
23
- const envelope = { value: event.data };
24
- if (event.kind === 'ext' && event.name === directiveEventName && isPageActionDirective(envelope)) {
25
- actions.push(envelope.value.action);
26
- }
27
- }
28
- return actions;
29
- }
30
- /** Returns only the first navigation and first page treatment. O(actions), O(1) extra space. */
31
- export function splitPageActions({ actions }) {
32
- return {
33
- navigate: actions.find((a) => a.type === 'navigate') ?? null,
34
- other: actions.find((a) => a.type !== 'navigate') ?? null,
35
- };
36
- }
37
- /** Exact title match first, case-insensitive fallback; never searches excluded UI. O(candidates). */
38
- export function findTargetElement({ title, root, selection }) {
39
- const needle = title.trim();
40
- if (!needle)
41
- return null;
42
- const candidates = Array.from(root.querySelectorAll(selection.candidateSelector))
43
- .filter(el => !el.closest(selection.excludedAncestorSelector));
44
- // `textContent` is null only for documents and doctypes; every Element the selector yields has a string.
45
- const text = (el) => el.textContent.trim();
46
- return candidates.find(el => text(el) === needle)
47
- ?? candidates.find(el => text(el).toLowerCase() === needle.toLowerCase()) ?? null;
48
- }
49
- /**
50
- * Creates page effects with injected DOM, navigation, URL policy, scroll and timers.
51
- * At most one highlight belongs to this instance; cleanup and navigation remove it.
52
- * URL policy is checked before queueing, navigation or page effects. Stale timers and descendant
53
- * animation events cannot remove the current highlight. Navigation paths are resolved by the host,
54
- * never guessed from a title; each controller owns its mutable highlight state.
55
- * @complexity Execute O(candidates); other operations O(1), with one timer/listener retained.
56
- */
57
- export function createBrowserPageActions(args) {
58
- if (!Number.isFinite(args.cleanupFallbackMs) || args.cleanupFallbackMs < 0)
59
- throw new Error('Invalid highlight deadline');
60
- let current = null;
61
- const clearHighlight = (_args) => {
62
- if (!current)
63
- return;
64
- const old = current;
65
- current = null;
66
- args.timers.cancel({ handle: old.handle });
67
- old.element.removeEventListener('animationend', old.onEnd);
68
- old.element.classList.remove(args.highlightClass);
69
- };
70
- function highlight(element) {
71
- if (current?.element === element)
72
- return;
73
- clearHighlight({});
74
- const onEnd = event => {
75
- if (event.target === element && event.animationName === args.fadeAnimationName)
76
- clearHighlight({});
77
- };
78
- element.classList.add(args.highlightClass);
79
- element.addEventListener('animationend', onEnd);
80
- // Identity check makes even a late callback from a canceled timer harmless.
81
- const handle = args.timers.schedule({ delayMs: args.cleanupFallbackMs, callback: () => {
82
- if (current?.element === element && current.onEnd === onEnd)
83
- clearHighlight({});
84
- } });
85
- current = { element, handle, onEnd };
86
- }
87
- const scrollToElement = ({ element }) => {
88
- args.scroll({ element, options: { behavior: args.reducedMotion({}) ? 'auto' : 'smooth', block: 'center' } });
89
- };
90
- return {
91
- applyHighlight({ element }) { highlight(element); },
92
- scrollToElement,
93
- allows({ action }) { return args.allowPath({ path: action.target.path }); },
94
- navigate({ action }) {
95
- if (!args.allowPath({ path: action.target.path }))
96
- return false;
97
- clearHighlight({});
98
- args.navigate({ path: action.target.path });
99
- return true;
100
- },
101
- execute({ action }) {
102
- if (!args.allowPath({ path: action.target.path }))
103
- return false;
104
- const element = findTargetElement({ title: action.target.title, root: args.root, selection: args.selection });
105
- if (!element)
106
- return false;
107
- scrollToElement({ element });
108
- if (action.type === 'highlight')
109
- highlight(element);
110
- return true;
111
- },
112
- clearHighlight,
113
- };
114
- }
115
- //# sourceMappingURL=page-actions.js.map
@@ -1,2 +0,0 @@
1
- export * from '../../core/browser/page-actions.js';
2
- //# sourceMappingURL=page-actions.d.ts.map
@@ -1,3 +0,0 @@
1
- // Compatibility path; shared page-action decisions belong to chat core.
2
- export * from '../../core/browser/page-actions.js';
3
- //# sourceMappingURL=page-actions.js.map