@agent-native/core 0.12.27 → 0.12.30
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.
- package/dist/agent/engine/builder-engine.d.ts +1 -1
- package/dist/agent/engine/builder-engine.d.ts.map +1 -1
- package/dist/agent/index.d.ts +1 -1
- package/dist/agent/index.d.ts.map +1 -1
- package/dist/agent/index.js.map +1 -1
- package/dist/agent/model-config.d.ts +3 -3
- package/dist/agent/model-config.d.ts.map +1 -1
- package/dist/agent/model-config.js +5 -4
- package/dist/agent/model-config.js.map +1 -1
- package/dist/agent/production-agent.d.ts +25 -1
- package/dist/agent/production-agent.d.ts.map +1 -1
- package/dist/agent/production-agent.js +47 -7
- package/dist/agent/production-agent.js.map +1 -1
- package/dist/application-state/emitter.d.ts +3 -2
- package/dist/application-state/emitter.d.ts.map +1 -1
- package/dist/application-state/emitter.js +4 -2
- package/dist/application-state/emitter.js.map +1 -1
- package/dist/application-state/store.js +3 -3
- package/dist/application-state/store.js.map +1 -1
- package/dist/client/AgentPanel.d.ts.map +1 -1
- package/dist/client/AgentPanel.js +0 -1
- package/dist/client/AgentPanel.js.map +1 -1
- package/dist/client/AssistantChat.d.ts.map +1 -1
- package/dist/client/AssistantChat.js +45 -7
- package/dist/client/AssistantChat.js.map +1 -1
- package/dist/client/MultiTabAssistantChat.js.map +1 -1
- package/dist/client/agent-chat-adapter.d.ts.map +1 -1
- package/dist/client/agent-chat-adapter.js +12 -5
- package/dist/client/agent-chat-adapter.js.map +1 -1
- package/dist/client/use-chat-models.js.map +1 -1
- package/dist/client/use-db-sync.d.ts +4 -0
- package/dist/client/use-db-sync.d.ts.map +1 -1
- package/dist/client/use-db-sync.js +38 -13
- package/dist/client/use-db-sync.js.map +1 -1
- package/dist/client/use-pausing-interval.d.ts.map +1 -1
- package/dist/client/use-pausing-interval.js +5 -2
- package/dist/client/use-pausing-interval.js.map +1 -1
- package/dist/collab/client.d.ts +2 -0
- package/dist/collab/client.d.ts.map +1 -1
- package/dist/collab/client.js +37 -4
- package/dist/collab/client.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/server/agent-chat-plugin.d.ts +25 -1
- package/dist/server/agent-chat-plugin.d.ts.map +1 -1
- package/dist/server/agent-chat-plugin.js +3 -0
- package/dist/server/agent-chat-plugin.js.map +1 -1
- package/dist/server/auth.d.ts.map +1 -1
- package/dist/server/auth.js +83 -2
- package/dist/server/auth.js.map +1 -1
- package/dist/server/google-auth-plugin.d.ts.map +1 -1
- package/dist/server/google-auth-plugin.js +50 -3
- package/dist/server/google-auth-plugin.js.map +1 -1
- package/dist/server/google-oauth.d.ts.map +1 -1
- package/dist/server/google-oauth.js +10 -4
- package/dist/server/google-oauth.js.map +1 -1
- package/dist/server/index.d.ts +1 -1
- package/dist/server/index.d.ts.map +1 -1
- package/dist/server/index.js.map +1 -1
- package/dist/server/onboarding-html.d.ts.map +1 -1
- package/dist/server/onboarding-html.js +50 -3
- package/dist/server/onboarding-html.js.map +1 -1
- package/dist/server/poll.d.ts.map +1 -1
- package/dist/server/poll.js +15 -0
- package/dist/server/poll.js.map +1 -1
- package/dist/templates/default/app/hooks/use-navigation-state.ts +0 -1
- package/package.json +1 -1
- package/src/templates/default/app/hooks/use-navigation-state.ts +0 -1
|
@@ -4,6 +4,9 @@ const POLL_ABORT_MIN_MS = 10_000;
|
|
|
4
4
|
function getPollAbortMs(interval) {
|
|
5
5
|
return Math.max(POLL_ABORT_MIN_MS, interval * 4);
|
|
6
6
|
}
|
|
7
|
+
function isDocumentHidden() {
|
|
8
|
+
return (typeof document !== "undefined" && document.visibilityState === "hidden");
|
|
9
|
+
}
|
|
7
10
|
async function fetchPollJson(pollUrl, since, interval) {
|
|
8
11
|
const controller = typeof AbortController === "undefined" ? null : new AbortController();
|
|
9
12
|
const timeout = controller
|
|
@@ -32,12 +35,14 @@ async function fetchPollJson(pollUrl, since, interval) {
|
|
|
32
35
|
* @param options.pollUrl - Poll endpoint URL. Default: "/_agent-native/poll"
|
|
33
36
|
* @param options.onEvent - Optional callback for each change event
|
|
34
37
|
* @param options.interval - Poll interval in ms. Default: 2000
|
|
38
|
+
* @param options.pauseWhenHidden - Pause polling while the tab is hidden.
|
|
39
|
+
* Default: true
|
|
35
40
|
* @param options.ignoreSource - Skip events whose `requestSource` matches this
|
|
36
41
|
* value. Use a per-tab ID so the UI ignores its own writes while still
|
|
37
42
|
* picking up changes from other tabs, agents, and scripts.
|
|
38
43
|
*/
|
|
39
44
|
export function useDbSync(options = {}) {
|
|
40
|
-
const { queryClient, queryKeys = ["data"], pollUrl = agentNativePath(options.eventsUrl ?? "/_agent-native/poll"), interval = 2000, } = options;
|
|
45
|
+
const { queryClient, queryKeys = ["data"], pollUrl = agentNativePath(options.eventsUrl ?? "/_agent-native/poll"), interval = 2000, pauseWhenHidden = true, } = options;
|
|
41
46
|
const onEventRef = useRef(options.onEvent);
|
|
42
47
|
onEventRef.current = options.onEvent;
|
|
43
48
|
const keysRef = useRef(queryKeys);
|
|
@@ -52,6 +57,8 @@ export function useDbSync(options = {}) {
|
|
|
52
57
|
function schedulePoll() {
|
|
53
58
|
if (stopped)
|
|
54
59
|
return;
|
|
60
|
+
if (pauseWhenHidden && isDocumentHidden())
|
|
61
|
+
return;
|
|
55
62
|
if (timer)
|
|
56
63
|
clearTimeout(timer);
|
|
57
64
|
timer = setTimeout(() => {
|
|
@@ -87,6 +94,10 @@ export function useDbSync(options = {}) {
|
|
|
87
94
|
queryClient.invalidateQueries({ queryKey: ["slot-available"] });
|
|
88
95
|
queryClient.invalidateQueries({ queryKey: ["tool"] });
|
|
89
96
|
queryClient.invalidateQueries({ queryKey: ["tools"] });
|
|
97
|
+
queryClient.invalidateQueries({ queryKey: ["app-state"] });
|
|
98
|
+
queryClient.invalidateQueries({ queryKey: ["navigate-command"] });
|
|
99
|
+
queryClient.invalidateQueries({ queryKey: ["show-questions"] });
|
|
100
|
+
queryClient.invalidateQueries({ queryKey: ["__set_url__"] });
|
|
90
101
|
}
|
|
91
102
|
// Always forward all events to onEvent — templates can decide
|
|
92
103
|
for (const evt of events) {
|
|
@@ -106,8 +117,7 @@ export function useDbSync(options = {}) {
|
|
|
106
117
|
}
|
|
107
118
|
}
|
|
108
119
|
function pollNow() {
|
|
109
|
-
if (
|
|
110
|
-
document.visibilityState === "hidden") {
|
|
120
|
+
if (pauseWhenHidden && isDocumentHidden()) {
|
|
111
121
|
return;
|
|
112
122
|
}
|
|
113
123
|
if (timer) {
|
|
@@ -117,11 +127,18 @@ export function useDbSync(options = {}) {
|
|
|
117
127
|
void poll();
|
|
118
128
|
}
|
|
119
129
|
function handleVisibilityChange() {
|
|
120
|
-
if (document.visibilityState === "visible")
|
|
130
|
+
if (document.visibilityState === "visible") {
|
|
121
131
|
pollNow();
|
|
132
|
+
}
|
|
133
|
+
else if (pauseWhenHidden && timer) {
|
|
134
|
+
clearTimeout(timer);
|
|
135
|
+
timer = null;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
// Initial poll immediately when visible. Hidden tabs catch up on focus.
|
|
139
|
+
if (!pauseWhenHidden || !isDocumentHidden()) {
|
|
140
|
+
void poll();
|
|
122
141
|
}
|
|
123
|
-
// Initial poll immediately
|
|
124
|
-
void poll();
|
|
125
142
|
window.addEventListener("focus", pollNow);
|
|
126
143
|
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
127
144
|
return () => {
|
|
@@ -131,7 +148,7 @@ export function useDbSync(options = {}) {
|
|
|
131
148
|
window.removeEventListener("focus", pollNow);
|
|
132
149
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
133
150
|
};
|
|
134
|
-
}, [pollUrl, queryClient, interval]);
|
|
151
|
+
}, [pollUrl, queryClient, interval, pauseWhenHidden]);
|
|
135
152
|
}
|
|
136
153
|
/** @deprecated Use useDbSync instead */
|
|
137
154
|
export const useFileWatcher = useDbSync;
|
|
@@ -155,7 +172,7 @@ export const useFileWatcher = useDbSync;
|
|
|
155
172
|
* );
|
|
156
173
|
*/
|
|
157
174
|
export function useScreenRefreshKey(options = {}) {
|
|
158
|
-
const { pollUrl = agentNativePath(options.pollUrl ?? "/_agent-native/poll"), interval = 2000, } = options;
|
|
175
|
+
const { pollUrl = agentNativePath(options.pollUrl ?? "/_agent-native/poll"), interval = 2000, pauseWhenHidden = true, } = options;
|
|
159
176
|
const [key, setKey] = useState(0);
|
|
160
177
|
useEffect(() => {
|
|
161
178
|
let versionRef = 0;
|
|
@@ -165,6 +182,8 @@ export function useScreenRefreshKey(options = {}) {
|
|
|
165
182
|
function schedulePoll() {
|
|
166
183
|
if (stopped)
|
|
167
184
|
return;
|
|
185
|
+
if (pauseWhenHidden && isDocumentHidden())
|
|
186
|
+
return;
|
|
168
187
|
if (timer)
|
|
169
188
|
clearTimeout(timer);
|
|
170
189
|
timer = setTimeout(() => {
|
|
@@ -192,8 +211,7 @@ export function useScreenRefreshKey(options = {}) {
|
|
|
192
211
|
}
|
|
193
212
|
}
|
|
194
213
|
function pollNow() {
|
|
195
|
-
if (
|
|
196
|
-
document.visibilityState === "hidden") {
|
|
214
|
+
if (pauseWhenHidden && isDocumentHidden()) {
|
|
197
215
|
return;
|
|
198
216
|
}
|
|
199
217
|
if (timer) {
|
|
@@ -203,10 +221,17 @@ export function useScreenRefreshKey(options = {}) {
|
|
|
203
221
|
void poll();
|
|
204
222
|
}
|
|
205
223
|
function handleVisibilityChange() {
|
|
206
|
-
if (document.visibilityState === "visible")
|
|
224
|
+
if (document.visibilityState === "visible") {
|
|
207
225
|
pollNow();
|
|
226
|
+
}
|
|
227
|
+
else if (pauseWhenHidden && timer) {
|
|
228
|
+
clearTimeout(timer);
|
|
229
|
+
timer = null;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
if (!pauseWhenHidden || !isDocumentHidden()) {
|
|
233
|
+
void poll();
|
|
208
234
|
}
|
|
209
|
-
void poll();
|
|
210
235
|
window.addEventListener("focus", pollNow);
|
|
211
236
|
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
212
237
|
return () => {
|
|
@@ -216,7 +241,7 @@ export function useScreenRefreshKey(options = {}) {
|
|
|
216
241
|
window.removeEventListener("focus", pollNow);
|
|
217
242
|
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
218
243
|
};
|
|
219
|
-
}, [pollUrl, interval]);
|
|
244
|
+
}, [pollUrl, interval, pauseWhenHidden]);
|
|
220
245
|
return key;
|
|
221
246
|
}
|
|
222
247
|
//# sourceMappingURL=use-db-sync.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-db-sync.js","sourceRoot":"","sources":["../../src/client/use-db-sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAMhD,MAAM,iBAAiB,GAAG,MAAM,CAAC;AAEjC,SAAS,cAAc,CAAC,QAAgB;IACtC,OAAO,IAAI,CAAC,GAAG,CAAC,iBAAiB,EAAE,QAAQ,GAAG,CAAC,CAAC,CAAC;AACnD,CAAC;AAED,KAAK,UAAU,aAAa,CAC1B,OAAe,EACf,KAAa,EACb,QAAgB;IAEhB,MAAM,UAAU,GACd,OAAO,eAAe,KAAK,WAAW,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,eAAe,EAAE,CAAC;IACxE,MAAM,OAAO,GAAG,UAAU;QACxB,CAAC,CAAC,UAAU,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,KAAK,EAAE,EAAE,cAAc,CAAC,QAAQ,CAAC,CAAC;QAChE,CAAC,CAAC,IAAI,CAAC;IAET,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,GAAG,OAAO,UAAU,KAAK,EAAE,EAC3B,UAAU,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,SAAS,CACvD,CAAC;QACF,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;QACnD,OAAO,GAAG,CAAC,IAAI,EAAE,CAAC;IACpB,CAAC;YAAS,CAAC;QACT,IAAI,OAAO;YAAE,YAAY,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;AACH,CAAC;AAED;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,SAAS,CACvB,UASI,EAAE;IAEN,MAAM,EACJ,WAAW,EACX,SAAS,GAAG,CAAC,MAAM,CAAC,EACpB,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,SAAS,IAAI,qBAAqB,CAAC,EACrE,QAAQ,GAAG,IAAI,GAChB,GAAG,OAAO,CAAC;IAEZ,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC3C,UAAU,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC;IAErC,MAAM,OAAO,GAAG,MAAM,CAAC,SAAS,CAAC,CAAC;IAClC,OAAO,CAAC,OAAO,GAAG,SAAS,CAAC;IAE5B,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,YAAY,CAAC,CAAC;IACrD,eAAe,CAAC,OAAO,GAAG,OAAO,CAAC,YAAY,CAAC;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,KAAK,GAAyC,IAAI,CAAC;QACvD,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,SAAS,YAAY;YACnB,IAAI,OAAO;gBAAE,OAAO;YACpB,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBACtB,KAAK,GAAG,IAAI,CAAC;gBACb,KAAK,IAAI,EAAE,CAAC;YACd,CAAC,EAAE,QAAQ,CAAC,CAAC;QACf,CAAC;QAED,KAAK,UAAU,IAAI;YACjB,IAAI,OAAO,IAAI,QAAQ;gBAAE,OAAO;YAChC,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAQ7B,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;gBAClC,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAQ3B,CAAC;gBAEF,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,WAAW,EAAE,CAAC;oBACrC,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,CAAC;oBACvC,MAAM,QAAQ,GAAG,MAAM;wBACrB,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAM,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,KAAK,MAAM,CAAC;wBACvD,CAAC,CAAC,MAAM,CAAC;oBAEX,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;wBACxB,KAAK,MAAM,GAAG,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;4BAClC,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;wBACrD,CAAC;wBAED,kEAAkE;wBAClE,4DAA4D;wBAC5D,8DAA8D;wBAC9D,2CAA2C;wBAC3C,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC;wBACxD,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE,CAAC,CAAC;wBAC3D,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;wBAC5D,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,iBAAiB,CAAC,EAAE,CAAC,CAAC;wBACjE,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC;wBAC/D,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,gBAAgB,CAAC,EAAE,CAAC,CAAC;wBAChE,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,MAAM,CAAC,EAAE,CAAC,CAAC;wBACtD,WAAW,CAAC,iBAAiB,CAAC,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;oBACzD,CAAC;oBAED,8DAA8D;oBAC9D,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;wBACzB,UAAU,CAAC,OAAO,EAAE,CAAC,GAAG,CAAC,CAAC;oBAC5B,CAAC;gBACH,CAAC;gBAED,8DAA8D;gBAC9D,uCAAuC;gBACvC,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,OAAO,CAAC,CAAC;YAC7C,CAAC;YAAC,MAAM,CAAC;gBACP,8CAA8C;YAChD,CAAC;oBAAS,CAAC;gBACT,QAAQ,GAAG,KAAK,CAAC;gBACjB,YAAY,EAAE,CAAC;YACjB,CAAC;QACH,CAAC;QAED,SAAS,OAAO;YACd,IACE,OAAO,QAAQ,KAAK,WAAW;gBAC/B,QAAQ,CAAC,eAAe,KAAK,QAAQ,EACrC,CAAC;gBACD,OAAO;YACT,CAAC;YACD,IAAI,KAAK,EAAE,CAAC;gBACV,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;YACD,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;QAED,SAAS,sBAAsB;YAC7B,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;QACxD,CAAC;QAED,2BAA2B;QAC3B,KAAK,IAAI,EAAE,CAAC;QACZ,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1C,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;QAEtE,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;QAC3E,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,wCAAwC;AACxC,MAAM,CAAC,MAAM,cAAc,GAAG,SAAS,CAAC;AAExC;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,mBAAmB,CACjC,UAAmD,EAAE;IAErD,MAAM,EACJ,OAAO,GAAG,eAAe,CAAC,OAAO,CAAC,OAAO,IAAI,qBAAqB,CAAC,EACnE,QAAQ,GAAG,IAAI,GAChB,GAAG,OAAO,CAAC;IACZ,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAElC,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,UAAU,GAAG,CAAC,CAAC;QACnB,IAAI,KAAK,GAAyC,IAAI,CAAC;QACvD,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,QAAQ,GAAG,KAAK,CAAC;QAErB,SAAS,YAAY;YACnB,IAAI,OAAO;gBAAE,OAAO;YACpB,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE;gBACtB,KAAK,GAAG,IAAI,CAAC;gBACb,KAAK,IAAI,EAAE,CAAC;YACd,CAAC,EAAE,QAAQ,CAAC,CAAC;QACf,CAAC;QAED,KAAK,UAAU,IAAI;YACjB,IAAI,OAAO,IAAI,QAAQ;gBAAE,OAAO;YAChC,QAAQ,GAAG,IAAI,CAAC;YAChB,IAAI,CAAC;gBACH,MAAM,IAAI,GAAG,MAAM,aAAa,CAG7B,OAAO,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;gBAClC,IAAI,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,gBAAgB,CAAC,EAAE,CAAC;oBAC5D,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;gBACvB,CAAC;gBACD,UAAU,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC;YAClD,CAAC;YAAC,MAAM,CAAC;gBACP,0CAA0C;YAC5C,CAAC;oBAAS,CAAC;gBACT,QAAQ,GAAG,KAAK,CAAC;gBACjB,YAAY,EAAE,CAAC;YACjB,CAAC;QACH,CAAC;QAED,SAAS,OAAO;YACd,IACE,OAAO,QAAQ,KAAK,WAAW;gBAC/B,QAAQ,CAAC,eAAe,KAAK,QAAQ,EACrC,CAAC;gBACD,OAAO;YACT,CAAC;YACD,IAAI,KAAK,EAAE,CAAC;gBACV,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;YACD,KAAK,IAAI,EAAE,CAAC;QACd,CAAC;QAED,SAAS,sBAAsB;YAC7B,IAAI,QAAQ,CAAC,eAAe,KAAK,SAAS;gBAAE,OAAO,EAAE,CAAC;QACxD,CAAC;QAED,KAAK,IAAI,EAAE,CAAC;QACZ,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1C,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;QAEtE,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,MAAM,CAAC,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YAC7C,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,sBAAsB,CAAC,CAAC;QAC3E,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;IAExB,OAAO,GAAG,CAAC;AACb,CAAC","sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { agentNativePath } from \"./api-path.js\";\n\ninterface QueryClient {\n invalidateQueries(opts?: { queryKey?: string[] }): void;\n}\n\nconst POLL_ABORT_MIN_MS = 10_000;\n\nfunction getPollAbortMs(interval: number): number {\n return Math.max(POLL_ABORT_MIN_MS, interval * 4);\n}\n\nasync function fetchPollJson<T>(\n pollUrl: string,\n since: number,\n interval: number,\n): Promise<T> {\n const controller =\n typeof AbortController === \"undefined\" ? null : new AbortController();\n const timeout = controller\n ? setTimeout(() => controller.abort(), getPollAbortMs(interval))\n : null;\n\n try {\n const res = await fetch(\n `${pollUrl}?since=${since}`,\n controller ? { signal: controller.signal } : undefined,\n );\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n return res.json();\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\n/**\n * Hook that polls /_agent-native/poll for DB change events and invalidates\n * react-query caches when changes are detected.\n *\n * Works in all deployment environments (serverless, edge, long-lived server).\n *\n * @param options.queryClient - The react-query QueryClient instance\n * @param options.queryKeys - Array of query key prefixes to invalidate on change.\n * Default: [\"data\"]\n * @param options.pollUrl - Poll endpoint URL. Default: \"/_agent-native/poll\"\n * @param options.onEvent - Optional callback for each change event\n * @param options.interval - Poll interval in ms. Default: 2000\n * @param options.ignoreSource - Skip events whose `requestSource` matches this\n * value. Use a per-tab ID so the UI ignores its own writes while still\n * picking up changes from other tabs, agents, and scripts.\n */\nexport function useDbSync(\n options: {\n queryClient?: QueryClient;\n queryKeys?: string[];\n pollUrl?: string;\n /** @deprecated Use pollUrl instead */\n eventsUrl?: string;\n onEvent?: (data: any) => void;\n interval?: number;\n ignoreSource?: string;\n } = {},\n): void {\n const {\n queryClient,\n queryKeys = [\"data\"],\n pollUrl = agentNativePath(options.eventsUrl ?? \"/_agent-native/poll\"),\n interval = 2000,\n } = options;\n\n const onEventRef = useRef(options.onEvent);\n onEventRef.current = options.onEvent;\n\n const keysRef = useRef(queryKeys);\n keysRef.current = queryKeys;\n\n const ignoreSourceRef = useRef(options.ignoreSource);\n ignoreSourceRef.current = options.ignoreSource;\n\n useEffect(() => {\n let versionRef = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let stopped = false;\n let inFlight = false;\n\n function schedulePoll() {\n if (stopped) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n void poll();\n }, interval);\n }\n\n async function poll() {\n if (stopped || inFlight) return;\n inFlight = true;\n try {\n const data = await fetchPollJson<{\n version: number;\n events: Array<{\n source: string;\n type: string;\n key?: string;\n requestSource?: string;\n }>;\n }>(pollUrl, versionRef, interval);\n const { version, events } = data as {\n version: number;\n events: Array<{\n source: string;\n type: string;\n key?: string;\n requestSource?: string;\n }>;\n };\n\n if (events.length > 0 && queryClient) {\n const ignore = ignoreSourceRef.current;\n const relevant = ignore\n ? events.filter((e: any) => e.requestSource !== ignore)\n : events;\n\n if (relevant.length > 0) {\n for (const key of keysRef.current) {\n queryClient.invalidateQueries({ queryKey: [key] });\n }\n\n // Framework-level invalidation: always invalidate framework query\n // keys on any non-own change event so that mutating actions\n // (agent or HTTP) auto-refresh the UI — regardless of how the\n // template configured queryKeys / onEvent.\n queryClient.invalidateQueries({ queryKey: [\"action\"] });\n queryClient.invalidateQueries({ queryKey: [\"extension\"] });\n queryClient.invalidateQueries({ queryKey: [\"extensions\"] });\n queryClient.invalidateQueries({ queryKey: [\"extension-slots\"] });\n queryClient.invalidateQueries({ queryKey: [\"slot-installs\"] });\n queryClient.invalidateQueries({ queryKey: [\"slot-available\"] });\n queryClient.invalidateQueries({ queryKey: [\"tool\"] });\n queryClient.invalidateQueries({ queryKey: [\"tools\"] });\n }\n\n // Always forward all events to onEvent — templates can decide\n for (const evt of events) {\n onEventRef.current?.(evt);\n }\n }\n\n // Never decrease — protects against serverless instances with\n // slightly different version counters.\n versionRef = Math.max(versionRef, version);\n } catch {\n // Network error — will retry on next interval\n } finally {\n inFlight = false;\n schedulePoll();\n }\n }\n\n function pollNow() {\n if (\n typeof document !== \"undefined\" &&\n document.visibilityState === \"hidden\"\n ) {\n return;\n }\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n void poll();\n }\n\n function handleVisibilityChange() {\n if (document.visibilityState === \"visible\") pollNow();\n }\n\n // Initial poll immediately\n void poll();\n window.addEventListener(\"focus\", pollNow);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n window.removeEventListener(\"focus\", pollNow);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [pollUrl, queryClient, interval]);\n}\n\n/** @deprecated Use useDbSync instead */\nexport const useFileWatcher = useDbSync;\n\n/**\n * Subscribe to `refresh-screen` events from the agent. Returns an integer\n * that increments every time the agent invokes the framework's `refresh-screen`\n * tool. Apply it as a React `key` on the main content wrapper (the part\n * OUTSIDE the agent chat sidebar) so that region remounts and re-fetches its\n * data while the chat, sidebar, and any other persistent chrome keep their\n * in-flight state.\n *\n * Usage in a template's root:\n *\n * const screenKey = useScreenRefreshKey();\n * return (\n * <AppLayout>\n * <div key={screenKey}>\n * <Outlet />\n * </div>\n * </AppLayout>\n * );\n */\nexport function useScreenRefreshKey(\n options: { pollUrl?: string; interval?: number } = {},\n): number {\n const {\n pollUrl = agentNativePath(options.pollUrl ?? \"/_agent-native/poll\"),\n interval = 2000,\n } = options;\n const [key, setKey] = useState(0);\n\n useEffect(() => {\n let versionRef = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let stopped = false;\n let inFlight = false;\n\n function schedulePoll() {\n if (stopped) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n void poll();\n }, interval);\n }\n\n async function poll() {\n if (stopped || inFlight) return;\n inFlight = true;\n try {\n const data = await fetchPollJson<{\n version: number;\n events: Array<{ source: string }>;\n }>(pollUrl, versionRef, interval);\n if (data.events?.some((e) => e.source === \"screen-refresh\")) {\n setKey((k) => k + 1);\n }\n versionRef = Math.max(versionRef, data.version);\n } catch {\n // Network error — retry on next interval.\n } finally {\n inFlight = false;\n schedulePoll();\n }\n }\n\n function pollNow() {\n if (\n typeof document !== \"undefined\" &&\n document.visibilityState === \"hidden\"\n ) {\n return;\n }\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n void poll();\n }\n\n function handleVisibilityChange() {\n if (document.visibilityState === \"visible\") pollNow();\n }\n\n void poll();\n window.addEventListener(\"focus\", pollNow);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n window.removeEventListener(\"focus\", pollNow);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [pollUrl, interval]);\n\n return key;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"use-db-sync.js","sourceRoot":"","sources":["../../src/client/use-db-sync.ts"],"names":[],"mappings":"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","sourcesContent":["import { useEffect, useRef, useState } from \"react\";\nimport { agentNativePath } from \"./api-path.js\";\n\ninterface QueryClient {\n invalidateQueries(opts?: { queryKey?: string[] }): void;\n}\n\nconst POLL_ABORT_MIN_MS = 10_000;\n\nfunction getPollAbortMs(interval: number): number {\n return Math.max(POLL_ABORT_MIN_MS, interval * 4);\n}\n\nfunction isDocumentHidden(): boolean {\n return (\n typeof document !== \"undefined\" && document.visibilityState === \"hidden\"\n );\n}\n\nasync function fetchPollJson<T>(\n pollUrl: string,\n since: number,\n interval: number,\n): Promise<T> {\n const controller =\n typeof AbortController === \"undefined\" ? null : new AbortController();\n const timeout = controller\n ? setTimeout(() => controller.abort(), getPollAbortMs(interval))\n : null;\n\n try {\n const res = await fetch(\n `${pollUrl}?since=${since}`,\n controller ? { signal: controller.signal } : undefined,\n );\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n return res.json();\n } finally {\n if (timeout) clearTimeout(timeout);\n }\n}\n\n/**\n * Hook that polls /_agent-native/poll for DB change events and invalidates\n * react-query caches when changes are detected.\n *\n * Works in all deployment environments (serverless, edge, long-lived server).\n *\n * @param options.queryClient - The react-query QueryClient instance\n * @param options.queryKeys - Array of query key prefixes to invalidate on change.\n * Default: [\"data\"]\n * @param options.pollUrl - Poll endpoint URL. Default: \"/_agent-native/poll\"\n * @param options.onEvent - Optional callback for each change event\n * @param options.interval - Poll interval in ms. Default: 2000\n * @param options.pauseWhenHidden - Pause polling while the tab is hidden.\n * Default: true\n * @param options.ignoreSource - Skip events whose `requestSource` matches this\n * value. Use a per-tab ID so the UI ignores its own writes while still\n * picking up changes from other tabs, agents, and scripts.\n */\nexport function useDbSync(\n options: {\n queryClient?: QueryClient;\n queryKeys?: string[];\n pollUrl?: string;\n /** @deprecated Use pollUrl instead */\n eventsUrl?: string;\n onEvent?: (data: any) => void;\n interval?: number;\n pauseWhenHidden?: boolean;\n ignoreSource?: string;\n } = {},\n): void {\n const {\n queryClient,\n queryKeys = [\"data\"],\n pollUrl = agentNativePath(options.eventsUrl ?? \"/_agent-native/poll\"),\n interval = 2000,\n pauseWhenHidden = true,\n } = options;\n\n const onEventRef = useRef(options.onEvent);\n onEventRef.current = options.onEvent;\n\n const keysRef = useRef(queryKeys);\n keysRef.current = queryKeys;\n\n const ignoreSourceRef = useRef(options.ignoreSource);\n ignoreSourceRef.current = options.ignoreSource;\n\n useEffect(() => {\n let versionRef = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let stopped = false;\n let inFlight = false;\n\n function schedulePoll() {\n if (stopped) return;\n if (pauseWhenHidden && isDocumentHidden()) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n void poll();\n }, interval);\n }\n\n async function poll() {\n if (stopped || inFlight) return;\n inFlight = true;\n try {\n const data = await fetchPollJson<{\n version: number;\n events: Array<{\n source: string;\n type: string;\n key?: string;\n requestSource?: string;\n }>;\n }>(pollUrl, versionRef, interval);\n const { version, events } = data as {\n version: number;\n events: Array<{\n source: string;\n type: string;\n key?: string;\n requestSource?: string;\n }>;\n };\n\n if (events.length > 0 && queryClient) {\n const ignore = ignoreSourceRef.current;\n const relevant = ignore\n ? events.filter((e: any) => e.requestSource !== ignore)\n : events;\n\n if (relevant.length > 0) {\n for (const key of keysRef.current) {\n queryClient.invalidateQueries({ queryKey: [key] });\n }\n\n // Framework-level invalidation: always invalidate framework query\n // keys on any non-own change event so that mutating actions\n // (agent or HTTP) auto-refresh the UI — regardless of how the\n // template configured queryKeys / onEvent.\n queryClient.invalidateQueries({ queryKey: [\"action\"] });\n queryClient.invalidateQueries({ queryKey: [\"extension\"] });\n queryClient.invalidateQueries({ queryKey: [\"extensions\"] });\n queryClient.invalidateQueries({ queryKey: [\"extension-slots\"] });\n queryClient.invalidateQueries({ queryKey: [\"slot-installs\"] });\n queryClient.invalidateQueries({ queryKey: [\"slot-available\"] });\n queryClient.invalidateQueries({ queryKey: [\"tool\"] });\n queryClient.invalidateQueries({ queryKey: [\"tools\"] });\n queryClient.invalidateQueries({ queryKey: [\"app-state\"] });\n queryClient.invalidateQueries({ queryKey: [\"navigate-command\"] });\n queryClient.invalidateQueries({ queryKey: [\"show-questions\"] });\n queryClient.invalidateQueries({ queryKey: [\"__set_url__\"] });\n }\n\n // Always forward all events to onEvent — templates can decide\n for (const evt of events) {\n onEventRef.current?.(evt);\n }\n }\n\n // Never decrease — protects against serverless instances with\n // slightly different version counters.\n versionRef = Math.max(versionRef, version);\n } catch {\n // Network error — will retry on next interval\n } finally {\n inFlight = false;\n schedulePoll();\n }\n }\n\n function pollNow() {\n if (pauseWhenHidden && isDocumentHidden()) {\n return;\n }\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n void poll();\n }\n\n function handleVisibilityChange() {\n if (document.visibilityState === \"visible\") {\n pollNow();\n } else if (pauseWhenHidden && timer) {\n clearTimeout(timer);\n timer = null;\n }\n }\n\n // Initial poll immediately when visible. Hidden tabs catch up on focus.\n if (!pauseWhenHidden || !isDocumentHidden()) {\n void poll();\n }\n window.addEventListener(\"focus\", pollNow);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n window.removeEventListener(\"focus\", pollNow);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [pollUrl, queryClient, interval, pauseWhenHidden]);\n}\n\n/** @deprecated Use useDbSync instead */\nexport const useFileWatcher = useDbSync;\n\n/**\n * Subscribe to `refresh-screen` events from the agent. Returns an integer\n * that increments every time the agent invokes the framework's `refresh-screen`\n * tool. Apply it as a React `key` on the main content wrapper (the part\n * OUTSIDE the agent chat sidebar) so that region remounts and re-fetches its\n * data while the chat, sidebar, and any other persistent chrome keep their\n * in-flight state.\n *\n * Usage in a template's root:\n *\n * const screenKey = useScreenRefreshKey();\n * return (\n * <AppLayout>\n * <div key={screenKey}>\n * <Outlet />\n * </div>\n * </AppLayout>\n * );\n */\nexport function useScreenRefreshKey(\n options: {\n pollUrl?: string;\n interval?: number;\n pauseWhenHidden?: boolean;\n } = {},\n): number {\n const {\n pollUrl = agentNativePath(options.pollUrl ?? \"/_agent-native/poll\"),\n interval = 2000,\n pauseWhenHidden = true,\n } = options;\n const [key, setKey] = useState(0);\n\n useEffect(() => {\n let versionRef = 0;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let stopped = false;\n let inFlight = false;\n\n function schedulePoll() {\n if (stopped) return;\n if (pauseWhenHidden && isDocumentHidden()) return;\n if (timer) clearTimeout(timer);\n timer = setTimeout(() => {\n timer = null;\n void poll();\n }, interval);\n }\n\n async function poll() {\n if (stopped || inFlight) return;\n inFlight = true;\n try {\n const data = await fetchPollJson<{\n version: number;\n events: Array<{ source: string }>;\n }>(pollUrl, versionRef, interval);\n if (data.events?.some((e) => e.source === \"screen-refresh\")) {\n setKey((k) => k + 1);\n }\n versionRef = Math.max(versionRef, data.version);\n } catch {\n // Network error — retry on next interval.\n } finally {\n inFlight = false;\n schedulePoll();\n }\n }\n\n function pollNow() {\n if (pauseWhenHidden && isDocumentHidden()) {\n return;\n }\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n void poll();\n }\n\n function handleVisibilityChange() {\n if (document.visibilityState === \"visible\") {\n pollNow();\n } else if (pauseWhenHidden && timer) {\n clearTimeout(timer);\n timer = null;\n }\n }\n\n if (!pauseWhenHidden || !isDocumentHidden()) {\n void poll();\n }\n window.addEventListener(\"focus\", pollNow);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n window.removeEventListener(\"focus\", pollNow);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [pollUrl, interval, pauseWhenHidden]);\n\n return key;\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-pausing-interval.d.ts","sourceRoot":"","sources":["../../src/client/use-pausing-interval.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACpC,MAAM,EAAE,MAAM,EACd,eAAe,GAAE,OAAc,GAC9B,IAAI,
|
|
1
|
+
{"version":3,"file":"use-pausing-interval.d.ts","sourceRoot":"","sources":["../../src/client/use-pausing-interval.ts"],"names":[],"mappings":"AAEA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,EACpC,MAAM,EAAE,MAAM,EACd,eAAe,GAAE,OAAc,GAC9B,IAAI,CAuCN"}
|
|
@@ -13,6 +13,7 @@ export function usePausingInterval(callback, pollMs, pauseWhenHidden = true) {
|
|
|
13
13
|
if (pollMs <= 0)
|
|
14
14
|
return;
|
|
15
15
|
let id = null;
|
|
16
|
+
const isHidden = () => typeof document !== "undefined" && document.hidden;
|
|
16
17
|
const start = () => {
|
|
17
18
|
if (id == null)
|
|
18
19
|
id = setInterval(callback, pollMs);
|
|
@@ -23,8 +24,8 @@ export function usePausingInterval(callback, pollMs, pauseWhenHidden = true) {
|
|
|
23
24
|
id = null;
|
|
24
25
|
}
|
|
25
26
|
};
|
|
26
|
-
callback();
|
|
27
27
|
if (!pauseWhenHidden) {
|
|
28
|
+
callback();
|
|
28
29
|
start();
|
|
29
30
|
return () => stop();
|
|
30
31
|
}
|
|
@@ -37,8 +38,10 @@ export function usePausingInterval(callback, pollMs, pauseWhenHidden = true) {
|
|
|
37
38
|
start();
|
|
38
39
|
}
|
|
39
40
|
};
|
|
40
|
-
if (!
|
|
41
|
+
if (!isHidden()) {
|
|
42
|
+
callback();
|
|
41
43
|
start();
|
|
44
|
+
}
|
|
42
45
|
document.addEventListener("visibilitychange", onVisibility);
|
|
43
46
|
return () => {
|
|
44
47
|
stop();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-pausing-interval.js","sourceRoot":"","sources":["../../src/client/use-pausing-interval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAoC,EACpC,MAAc,EACd,kBAA2B,IAAI;IAE/B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,IAAI,CAAC;YAAE,OAAO;QACxB,IAAI,EAAE,GAA0C,IAAI,CAAC;QACrD,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,IAAI,EAAE,IAAI,IAAI;gBAAE,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;gBACf,aAAa,CAAC,EAAE,CAAC,CAAC;gBAClB,EAAE,GAAG,IAAI,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QAEF,
|
|
1
|
+
{"version":3,"file":"use-pausing-interval.js","sourceRoot":"","sources":["../../src/client/use-pausing-interval.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,QAAoC,EACpC,MAAc,EACd,kBAA2B,IAAI;IAE/B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,MAAM,IAAI,CAAC;YAAE,OAAO;QACxB,IAAI,EAAE,GAA0C,IAAI,CAAC;QACrD,MAAM,QAAQ,GAAG,GAAG,EAAE,CAAC,OAAO,QAAQ,KAAK,WAAW,IAAI,QAAQ,CAAC,MAAM,CAAC;QAC1E,MAAM,KAAK,GAAG,GAAG,EAAE;YACjB,IAAI,EAAE,IAAI,IAAI;gBAAE,EAAE,GAAG,WAAW,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QACrD,CAAC,CAAC;QACF,MAAM,IAAI,GAAG,GAAG,EAAE;YAChB,IAAI,EAAE,IAAI,IAAI,EAAE,CAAC;gBACf,aAAa,CAAC,EAAE,CAAC,CAAC;gBAClB,EAAE,GAAG,IAAI,CAAC;YACZ,CAAC;QACH,CAAC,CAAC;QAEF,IAAI,CAAC,eAAe,EAAE,CAAC;YACrB,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,CAAC;YACR,OAAO,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC;QACtB,CAAC;QAED,MAAM,YAAY,GAAG,GAAG,EAAE;YACxB,IAAI,QAAQ,CAAC,MAAM,EAAE,CAAC;gBACpB,IAAI,EAAE,CAAC;YACT,CAAC;iBAAM,CAAC;gBACN,QAAQ,EAAE,CAAC;gBACX,KAAK,EAAE,CAAC;YACV,CAAC;QACH,CAAC,CAAC;QACF,IAAI,CAAC,QAAQ,EAAE,EAAE,CAAC;YAChB,QAAQ,EAAE,CAAC;YACX,KAAK,EAAE,CAAC;QACV,CAAC;QACD,QAAQ,CAAC,gBAAgB,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QAC5D,OAAO,GAAG,EAAE;YACV,IAAI,EAAE,CAAC;YACP,QAAQ,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAC;QACjE,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,eAAe,CAAC,CAAC,CAAC;AAC1C,CAAC","sourcesContent":["import { useEffect } from \"react\";\n\n/**\n * Runs `callback` on an interval, pausing when the tab becomes hidden and\n * resuming (with an immediate re-run) when the tab becomes visible again.\n * Fires `callback` once immediately on mount (if the tab is visible).\n *\n * Pass `pollMs=0` to disable. Pass `pauseWhenHidden=false` to keep the\n * interval running even when the tab is hidden — the bell's browser-\n * notification popup loop uses that to still reach backgrounded tabs.\n */\nexport function usePausingInterval(\n callback: () => void | Promise<void>,\n pollMs: number,\n pauseWhenHidden: boolean = true,\n): void {\n useEffect(() => {\n if (pollMs <= 0) return;\n let id: ReturnType<typeof setInterval> | null = null;\n const isHidden = () => typeof document !== \"undefined\" && document.hidden;\n const start = () => {\n if (id == null) id = setInterval(callback, pollMs);\n };\n const stop = () => {\n if (id != null) {\n clearInterval(id);\n id = null;\n }\n };\n\n if (!pauseWhenHidden) {\n callback();\n start();\n return () => stop();\n }\n\n const onVisibility = () => {\n if (document.hidden) {\n stop();\n } else {\n callback();\n start();\n }\n };\n if (!isHidden()) {\n callback();\n start();\n }\n document.addEventListener(\"visibilitychange\", onVisibility);\n return () => {\n stop();\n document.removeEventListener(\"visibilitychange\", onVisibility);\n };\n }, [callback, pollMs, pauseWhenHidden]);\n}\n"]}
|
package/dist/collab/client.d.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface UseCollaborativeDocOptions {
|
|
|
20
20
|
docId: string | null;
|
|
21
21
|
/** Poll interval in ms. Default: 2000 */
|
|
22
22
|
pollInterval?: number;
|
|
23
|
+
/** Pause remote update/presence polling while the tab is hidden. Default: true */
|
|
24
|
+
pauseWhenHidden?: boolean;
|
|
23
25
|
/** Base URL for collab endpoints. Default: "/_agent-native/collab" */
|
|
24
26
|
baseUrl?: string;
|
|
25
27
|
/** Request source ID for jitter prevention (e.g., tab ID). */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/collab/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,4EAA4E;IAC5E,IAAI,EAAE,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;IACnB,uDAAuD;IACvD,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,YAAY,EAAE,OAAO,CAAC;CACvB;AAgBD,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/collab/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAGH,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAGlD,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,0BAA0B;IACzC,2DAA2D;IAC3D,KAAK,EAAE,MAAM,GAAG,IAAI,CAAC;IACrB,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,kFAAkF;IAClF,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,sEAAsE;IACtE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;AAED,MAAM,WAAW,yBAAyB;IACxC,4EAA4E;IAC5E,IAAI,EAAE,CAAC,CAAC,GAAG,GAAG,IAAI,CAAC;IACnB,uDAAuD;IACvD,SAAS,EAAE,SAAS,GAAG,IAAI,CAAC;IAC5B,kEAAkE;IAClE,SAAS,EAAE,OAAO,CAAC;IACnB,iDAAiD;IACjD,QAAQ,EAAE,OAAO,CAAC;IAClB,sDAAsD;IACtD,WAAW,EAAE,UAAU,EAAE,CAAC;IAC1B,6EAA6E;IAC7E,WAAW,EAAE,OAAO,CAAC;IACrB,+EAA+E;IAC/E,YAAY,EAAE,OAAO,CAAC;CACvB;AAgBD,4DAA4D;AAC5D,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAMlD;AAED,mDAAmD;AACnD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGjD;AAYD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,UAAU,EAAE,GAAG,UAAU,EAAE,CAY1E;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;CAChB;AAED,wBAAgB,8BAA8B,CAC5C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,EAC5B,aAAa,EAAE,MAAM,EACrB,YAAY,EAAE,uBAAuB,EAAE,GACtC;IAAE,KAAK,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,CA2B3D;AAoBD,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,0BAA0B,GAClC,yBAAyB,CAuS3B"}
|
package/dist/collab/client.js
CHANGED
|
@@ -41,6 +41,9 @@ export function emailToName(email) {
|
|
|
41
41
|
function normalizeCollabEmail(email) {
|
|
42
42
|
return email.trim().toLowerCase();
|
|
43
43
|
}
|
|
44
|
+
function isDocumentHidden() {
|
|
45
|
+
return (typeof document !== "undefined" && document.visibilityState === "hidden");
|
|
46
|
+
}
|
|
44
47
|
export function dedupeCollabUsersByEmail(users) {
|
|
45
48
|
const byEmail = new Map();
|
|
46
49
|
for (const user of users) {
|
|
@@ -97,7 +100,7 @@ function base64ToUint8Array(b64) {
|
|
|
97
100
|
return arr;
|
|
98
101
|
}
|
|
99
102
|
export function useCollaborativeDoc(options) {
|
|
100
|
-
const { docId, pollInterval = 2000, baseUrl = agentNativePath("/_agent-native/collab"), requestSource, user, } = options;
|
|
103
|
+
const { docId, pollInterval = 2000, pauseWhenHidden = true, baseUrl = agentNativePath("/_agent-native/collab"), requestSource, user, } = options;
|
|
101
104
|
// Stable Y.Doc per docId
|
|
102
105
|
const ydoc = useMemo(() => {
|
|
103
106
|
if (!docId)
|
|
@@ -230,6 +233,13 @@ export function useCollaborativeDoc(options) {
|
|
|
230
233
|
return;
|
|
231
234
|
let stopped = false;
|
|
232
235
|
let timer = null;
|
|
236
|
+
function schedulePoll() {
|
|
237
|
+
if (stopped)
|
|
238
|
+
return;
|
|
239
|
+
if (pauseWhenHidden && isDocumentHidden())
|
|
240
|
+
return;
|
|
241
|
+
timer = setTimeout(poll, pollInterval);
|
|
242
|
+
}
|
|
233
243
|
async function poll() {
|
|
234
244
|
if (stopped)
|
|
235
245
|
return;
|
|
@@ -295,21 +305,44 @@ export function useCollaborativeDoc(options) {
|
|
|
295
305
|
catch {
|
|
296
306
|
// Network error — retry next interval
|
|
297
307
|
}
|
|
298
|
-
|
|
299
|
-
|
|
308
|
+
schedulePoll();
|
|
309
|
+
}
|
|
310
|
+
function pollNow() {
|
|
311
|
+
if (pauseWhenHidden && isDocumentHidden())
|
|
312
|
+
return;
|
|
313
|
+
if (timer) {
|
|
314
|
+
clearTimeout(timer);
|
|
315
|
+
timer = null;
|
|
316
|
+
}
|
|
317
|
+
void poll();
|
|
318
|
+
}
|
|
319
|
+
function handleVisibilityChange() {
|
|
320
|
+
if (document.visibilityState === "visible") {
|
|
321
|
+
pollNow();
|
|
300
322
|
}
|
|
323
|
+
else if (pauseWhenHidden && timer) {
|
|
324
|
+
clearTimeout(timer);
|
|
325
|
+
timer = null;
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (!pauseWhenHidden || !isDocumentHidden()) {
|
|
329
|
+
void poll();
|
|
301
330
|
}
|
|
302
|
-
|
|
331
|
+
window.addEventListener("focus", pollNow);
|
|
332
|
+
document.addEventListener("visibilitychange", handleVisibilityChange);
|
|
303
333
|
return () => {
|
|
304
334
|
stopped = true;
|
|
305
335
|
if (timer)
|
|
306
336
|
clearTimeout(timer);
|
|
337
|
+
window.removeEventListener("focus", pollNow);
|
|
338
|
+
document.removeEventListener("visibilitychange", handleVisibilityChange);
|
|
307
339
|
};
|
|
308
340
|
}, [
|
|
309
341
|
ydoc,
|
|
310
342
|
awareness,
|
|
311
343
|
docId,
|
|
312
344
|
pollInterval,
|
|
345
|
+
pauseWhenHidden,
|
|
313
346
|
requestSource,
|
|
314
347
|
baseUrl,
|
|
315
348
|
docMissing,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/collab/client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC7D,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;AACzB,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAsCxD,4CAA4C;AAC5C,MAAM,aAAa,GAAG;IACpB,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;IACT,SAAS;CACV,CAAC;AAEF,4DAA4D;AAC5D,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,IAAI,IAAI,GAAG,CAAC,CAAC;IACb,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,GAAG,IAAI,GAAG,KAAK,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACxD,CAAC;IACD,OAAO,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC;AAC9D,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,WAAW,CAAC,KAAa;IACvC,MAAM,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC;IAC3C,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAa;IACzC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AACpC,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAmB;IAC1D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAsB,CAAC;IAC9C,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,oBAAoB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;QAC/C,IAAI,CAAC,KAAK,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC;YAAE,SAAS;QAC3C,OAAO,CAAC,GAAG,CAAC,KAAK,EAAE;YACjB,IAAI,EAAE,IAAI,CAAC,IAAI,IAAI,WAAW,CAAC,KAAK,CAAC;YACrC,KAAK;YACL,KAAK,EAAE,IAAI,CAAC,KAAK,IAAI,YAAY,CAAC,KAAK,CAAC;SACzC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;AACtC,CAAC;AAOD,MAAM,UAAU,8BAA8B,CAC5C,MAA4B,EAC5B,aAAqB,EACrB,YAAuC;IAEvC,MAAM,QAAQ,GAAG,IAAI,GAAG,EAAU,CAAC;IACnC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAa,EAAE,CAAC;IAE7B,KAAK,MAAM,MAAM,IAAI,YAAY,EAAE,CAAC;QAClC,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,QAAQ,CAAC;YACjC,MAAM,CAAC,QAAQ,KAAK,aAAa,EACjC,CAAC;YACD,SAAS;QACX,CAAC;QACD,QAAQ,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC9B,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,GAAG,CAAC,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC;QAC1C,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;IACrD,CAAC;IAED,KAAK,MAAM,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;QACjD,IAAI,QAAQ,KAAK,aAAa;YAAE,SAAS;QACzC,IAAI,QAAQ,CAAC,GAAG,CAAC,QAAQ,CAAC;YAAE,SAAS;QACrC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QACxB,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACzB,CAAC;IAED,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AACrC,CAAC;AAED,iBAAiB;AACjB,SAAS,kBAAkB,CAAC,GAAe;IACzC,IAAI,MAAM,GAAG,EAAE,CAAC;IAChB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACpC,MAAM,IAAI,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;IACxC,CAAC;IACD,OAAO,IAAI,CAAC,MAAM,CAAC,CAAC;AACtB,CAAC;AAED,SAAS,kBAAkB,CAAC,GAAW;IACrC,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;IACzB,MAAM,GAAG,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAC1C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,GAAG,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,UAAU,mBAAmB,CACjC,OAAmC;IAEnC,MAAM,EACJ,KAAK,EACL,YAAY,GAAG,IAAI,EACnB,OAAO,GAAG,eAAe,CAAC,uBAAuB,CAAC,EAClD,aAAa,EACb,IAAI,GACL,GAAG,OAAO,CAAC;IAEZ,yBAAyB;IACzB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,EAAE;QACxB,IAAI,CAAC,KAAK;YAAE,OAAO,IAAI,CAAC;QACxB,OAAO,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC;IACrB,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,CAAC;IAEZ,4BAA4B;IAC5B,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,EAAE;QAC7B,IAAI,CAAC,IAAI;YAAE,OAAO,IAAI,CAAC;QACvB,OAAO,IAAI,SAAS,CAAC,IAAI,CAAC,CAAC;IAC7B,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;IAEX,MAAM,CAAC,SAAS,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,CAAC,QAAQ,EAAE,WAAW,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAChD,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAe,EAAE,CAAC,CAAC;IACjE,MAAM,CAAC,WAAW,EAAE,cAAc,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACtD,MAAM,CAAC,YAAY,EAAE,eAAe,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACxD,yEAAyE;IACzE,2EAA2E;IAC3E,6BAA6B;IAC7B,MAAM,CAAC,UAAU,EAAE,aAAa,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IACpD,MAAM,aAAa,GAAG,MAAM,CAAuC,IAAI,CAAC,CAAC;IACzE,MAAM,cAAc,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAEjC,0DAA0D;IAC1D,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS,IAAI,CAAC,IAAI;YAAE,OAAO;QAChC,SAAS,CAAC,kBAAkB,CAAC,MAAM,EAAE;YACnC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;SAClB,CAAC,CAAC;IACL,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC;IAEtD,4CAA4C;IAC5C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,SAAS;YAAE,OAAO;QAEvB,MAAM,WAAW,GAAG,GAAG,EAAE;YACvB,MAAM,KAAK,GAAiB,EAAE,CAAC;YAC/B,IAAI,QAAQ,GAAG,KAAK,CAAC;YACrB,SAAS,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;gBAChD,IAAI,QAAQ,KAAK,IAAI,EAAE,QAAQ;oBAAE,OAAO,CAAC,YAAY;gBACrD,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC;oBACf,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,IAAkB,CAAC,CAAC;oBACrC,IAAK,KAAK,CAAC,IAAmB,CAAC,KAAK,KAAK,cAAc,EAAE,CAAC;wBACxD,QAAQ,GAAG,IAAI,CAAC;oBAClB,CAAC;gBACH,CAAC;YACH,CAAC,CAAC,CAAC;YACH,cAAc,CAAC,wBAAwB,CAAC,KAAK,CAAC,CAAC,CAAC;YAChD,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC5B,CAAC,CAAC;QAEF,SAAS,CAAC,EAAE,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACpC,OAAO,GAAG,EAAE;YACV,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;QACvC,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,SAAS,EAAE,IAAI,CAAC,CAAC,CAAC;IAEtB,sCAAsC;IACtC,SAAS,CAAC,GAAG,EAAE;QACb,OAAO,GAAG,EAAE;YACV,SAAS,EAAE,OAAO,EAAE,CAAC;YACrB,IAAI,EAAE,OAAO,EAAE,CAAC;QAClB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC;IAEtB,+CAA+C;IAC/C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;YACpB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO;QACT,CAAC;QAED,IAAI,SAAS,GAAG,KAAK,CAAC;QACtB,YAAY,CAAC,IAAI,CAAC,CAAC;QACnB,WAAW,CAAC,KAAK,CAAC,CAAC;QACnB,aAAa,CAAC,KAAK,CAAC,CAAC;QAErB,KAAK,CAAC,GAAG,OAAO,IAAI,KAAK,QAAQ,CAAC;aAC/B,IAAI,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;YAClB,IAAI,SAAS;gBAAE,OAAO;YACtB,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBAC7C,aAAa,CAAC,IAAI,CAAC,CAAC;gBACpB,YAAY,CAAC,KAAK,CAAC,CAAC;gBACpB,WAAW,CAAC,IAAI,CAAC,CAAC;gBAClB,OAAO;YACT,CAAC;YACD,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAExC,CAAC;YACT,IAAI,IAAI,EAAE,KAAK,EAAE,CAAC;gBAChB,MAAM,MAAM,GAAG,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;gBAC9C,IAAI,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACtB,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;gBAC9B,CAAC;YACH,CAAC;YACD,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,CAAC;aACD,KAAK,CAAC,GAAG,EAAE;YACV,IAAI,SAAS;gBAAE,OAAO;YACtB,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,WAAW,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC,CAAC,CAAC;QAEL,OAAO,GAAG,EAAE;YACV,SAAS,GAAG,IAAI,CAAC;QACnB,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;IAE3B,+BAA+B;IAC/B,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,UAAU;YAAE,OAAO;QAE1C,MAAM,OAAO,GAAG,CAAC,MAAkB,EAAE,MAAe,EAAE,EAAE;YACtD,IAAI,MAAM,KAAK,QAAQ;gBAAE,OAAO;YAEhC,KAAK,CAAC,GAAG,OAAO,IAAI,KAAK,SAAS,EAAE;gBAClC,MAAM,EAAE,MAAM;gBACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;gBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;oBACnB,MAAM,EAAE,kBAAkB,CAAC,MAAM,CAAC;oBAClC,aAAa;iBACd,CAAC;aACH,CAAC,CAAC;QACL,CAAC,CAAC;QAEF,IAAI,CAAC,EAAE,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC3B,OAAO,GAAG,EAAE;YACV,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QAC9B,CAAC,CAAC;IACJ,CAAC,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,aAAa,EAAE,UAAU,CAAC,CAAC,CAAC;IAEtD,+CAA+C;IAC/C,SAAS,CAAC,GAAG,EAAE;QACb,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,IAAI,UAAU;YAAE,OAAO;QAE1C,IAAI,OAAO,GAAG,KAAK,CAAC;QACpB,IAAI,KAAK,GAAyC,IAAI,CAAC;QAEvD,KAAK,UAAU,IAAI;YACjB,IAAI,OAAO;gBAAE,OAAO;YACpB,IAAI,CAAC;gBACH,4BAA4B;gBAC5B,MAAM,GAAG,GAAG,MAAM,KAAK,CACrB,eAAe,CACb,6BAA6B,cAAc,CAAC,OAAO,EAAE,CACtD,CACF,CAAC;gBACF,IAAI,CAAC,GAAG,CAAC,EAAE;oBAAE,MAAM,IAAI,KAAK,CAAC,OAAO,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;gBACnD,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,IAAI,EAAE,CAAC;gBAC9B,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,IAQ3B,CAAC;gBAEF,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;oBACzB,IAAI,GAAG,CAAC,MAAM,KAAK,QAAQ,IAAI,GAAG,CAAC,KAAK,KAAK,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;wBACjE,IAAI,aAAa,IAAI,GAAG,CAAC,aAAa,KAAK,aAAa;4BAAE,SAAS;wBACnE,CAAC,CAAC,WAAW,CAAC,IAAI,EAAE,kBAAkB,CAAC,GAAG,CAAC,MAAM,CAAC,EAAE,QAAQ,CAAC,CAAC;wBAE9D,wCAAwC;wBACxC,IAAI,GAAG,CAAC,aAAa,KAAK,OAAO,EAAE,CAAC;4BAClC,cAAc,CAAC,IAAI,CAAC,CAAC;4BACrB,IAAI,aAAa,CAAC,OAAO;gCAAE,YAAY,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;4BAC/D,aAAa,CAAC,OAAO,GAAG,UAAU,CAChC,GAAG,EAAE,CAAC,cAAc,CAAC,KAAK,CAAC,EAC3B,IAAI,CACL,CAAC;wBACJ,CAAC;oBACH,CAAC;gBACH,CAAC;gBAED,cAAc,CAAC,OAAO,GAAG,OAAO,CAAC;gBAEjC,oCAAoC;gBACpC,IAAI,SAAS,EAAE,CAAC;oBACd,MAAM,UAAU,GAAG,SAAS,CAAC,aAAa,EAAE,CAAC;oBAC7C,IAAI,UAAU,EAAE,CAAC;wBACf,MAAM,YAAY,GAAG,MAAM,KAAK,CAAC,GAAG,OAAO,IAAI,KAAK,YAAY,EAAE;4BAChE,MAAM,EAAE,MAAM;4BACd,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;4BAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gCACnB,QAAQ,EAAE,IAAI,CAAC,QAAQ;gCACvB,KAAK,EAAE,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC;6BAClC,CAAC;yBACH,CAAC,CAAC;wBACH,IAAI,YAAY,CAAC,EAAE,EAAE,CAAC;4BACpB,MAAM,aAAa,GAAG,MAAM,YAAY,CAAC,IAAI,EAAE,CAAC;4BAChD,MAAM,YAAY,GAA8B,EAAE,CAAC;4BACnD,KAAK,MAAM,MAAM,IAAI,aAAa,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC;gCAChD,IAAI,CAAC;oCACH,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oCAC7C,YAAY,CAAC,IAAI,CAAC;wCAChB,QAAQ,EAAE,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC;wCACjC,KAAK,EAAE,WAAW;qCACnB,CAAC,CAAC;gCACL,CAAC;gCAAC,MAAM,CAAC;oCACP,uBAAuB;gCACzB,CAAC;4BACH,CAAC;4BACD,MAAM,OAAO,GAAG,8BAA8B,CAC5C,SAAS,CAAC,SAAS,EAA0B,EAC7C,IAAI,CAAC,QAAQ,EACb,YAAY,CACb,CAAC;4BACF,IACE,OAAO,CAAC,KAAK,CAAC,MAAM;gCACpB,OAAO,CAAC,OAAO,CAAC,MAAM;gCACtB,OAAO,CAAC,OAAO,CAAC,MAAM,EACtB,CAAC;gCACD,SAAS,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC;4BAChD,CAAC;wBACH,CAAC;oBACH,CAAC;gBACH,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,sCAAsC;YACxC,CAAC;YACD,IAAI,CAAC,OAAO,EAAE,CAAC;gBACb,KAAK,GAAG,UAAU,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;YACzC,CAAC;QACH,CAAC;QAED,IAAI,EAAE,CAAC;QAEP,OAAO,GAAG,EAAE;YACV,OAAO,GAAG,IAAI,CAAC;YACf,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;QACjC,CAAC,CAAC;IACJ,CAAC,EAAE;QACD,IAAI;QACJ,SAAS;QACT,KAAK;QACL,YAAY;QACZ,aAAa;QACb,OAAO;QACP,UAAU;KACX,CAAC,CAAC;IAEH,OAAO;QACL,IAAI;QACJ,SAAS;QACT,SAAS;QACT,QAAQ;QACR,WAAW;QACX,WAAW;QACX,YAAY;KACb,CAAC;AACJ,CAAC","sourcesContent":["/**\n * Client-side hook for collaborative document editing via Yjs.\n *\n * Creates a STABLE Y.Doc per docId that never changes identity. This allows\n * TipTap's Collaboration extension to bind once without editor recreation.\n * Server state is applied to the existing doc when it arrives.\n *\n * Also manages Yjs Awareness for cursor positions and user presence,\n * synced via polling to the server's awareness endpoint.\n */\n\nimport { useEffect, useRef, useState, useMemo } from \"react\";\nimport * as Y from \"yjs\";\nimport { Awareness } from \"y-protocols/awareness\";\nimport { agentNativePath } from \"../client/api-path.js\";\n\nexport interface CollabUser {\n name: string;\n email: string;\n color: string;\n}\n\nexport interface UseCollaborativeDocOptions {\n /** Document ID to collaborate on. Pass null to disable. */\n docId: string | null;\n /** Poll interval in ms. Default: 2000 */\n pollInterval?: number;\n /** Base URL for collab endpoints. Default: \"/_agent-native/collab\" */\n baseUrl?: string;\n /** Request source ID for jitter prevention (e.g., tab ID). */\n requestSource?: string;\n /** Current user info for cursor labels. */\n user?: CollabUser;\n}\n\nexport interface UseCollaborativeDocResult {\n /** The Yjs document instance. Stable per docId — never changes identity. */\n ydoc: Y.Doc | null;\n /** Yjs Awareness instance for cursor/presence sync. */\n awareness: Awareness | null;\n /** Whether the initial state is still loading from the server. */\n isLoading: boolean;\n /** Whether the doc is synced with the server. */\n isSynced: boolean;\n /** Active users on this document (from awareness). */\n activeUsers: CollabUser[];\n /** True briefly when the AI agent makes an edit (for presence indicator). */\n agentActive: boolean;\n /** True when the AI agent has an active awareness entry (durable presence). */\n agentPresent: boolean;\n}\n\n// Consistent color palette for user cursors\nconst CURSOR_COLORS = [\n \"#f87171\",\n \"#fb923c\",\n \"#fbbf24\",\n \"#a3e635\",\n \"#34d399\",\n \"#22d3ee\",\n \"#60a5fa\",\n \"#a78bfa\",\n \"#f472b6\",\n \"#e879f9\",\n];\n\n/** Hash a string to a consistent color from the palette. */\nexport function emailToColor(email: string): string {\n let hash = 0;\n for (let i = 0; i < email.length; i++) {\n hash = ((hash << 5) - hash + email.charCodeAt(i)) | 0;\n }\n return CURSOR_COLORS[Math.abs(hash) % CURSOR_COLORS.length];\n}\n\n/** Derive a display name from an email address. */\nexport function emailToName(email: string): string {\n const local = email.split(\"@\")[0] || email;\n return local.charAt(0).toUpperCase() + local.slice(1);\n}\n\nfunction normalizeCollabEmail(email: string): string {\n return email.trim().toLowerCase();\n}\n\nexport function dedupeCollabUsersByEmail(users: CollabUser[]): CollabUser[] {\n const byEmail = new Map<string, CollabUser>();\n for (const user of users) {\n const email = normalizeCollabEmail(user.email);\n if (!email || byEmail.has(email)) continue;\n byEmail.set(email, {\n name: user.name || emailToName(email),\n email,\n color: user.color || emailToColor(email),\n });\n }\n return Array.from(byEmail.values());\n}\n\nexport interface RemoteAwarenessSnapshot {\n clientId: number;\n state: unknown;\n}\n\nexport function reconcileRemoteAwarenessStates(\n states: Map<number, unknown>,\n localClientId: number,\n remoteStates: RemoteAwarenessSnapshot[],\n): { added: number[]; updated: number[]; removed: number[] } {\n const incoming = new Set<number>();\n const added: number[] = [];\n const updated: number[] = [];\n const removed: number[] = [];\n\n for (const remote of remoteStates) {\n if (\n !Number.isFinite(remote.clientId) ||\n remote.clientId === localClientId\n ) {\n continue;\n }\n incoming.add(remote.clientId);\n const hadState = states.has(remote.clientId);\n states.set(remote.clientId, remote.state);\n (hadState ? updated : added).push(remote.clientId);\n }\n\n for (const clientId of Array.from(states.keys())) {\n if (clientId === localClientId) continue;\n if (incoming.has(clientId)) continue;\n states.delete(clientId);\n removed.push(clientId);\n }\n\n return { added, updated, removed };\n}\n\n// Base64 helpers\nfunction uint8ArrayToBase64(arr: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < arr.length; i++) {\n binary += String.fromCharCode(arr[i]);\n }\n return btoa(binary);\n}\n\nfunction base64ToUint8Array(b64: string): Uint8Array {\n const binary = atob(b64);\n const arr = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n arr[i] = binary.charCodeAt(i);\n }\n return arr;\n}\n\nexport function useCollaborativeDoc(\n options: UseCollaborativeDocOptions,\n): UseCollaborativeDocResult {\n const {\n docId,\n pollInterval = 2000,\n baseUrl = agentNativePath(\"/_agent-native/collab\"),\n requestSource,\n user,\n } = options;\n\n // Stable Y.Doc per docId\n const ydoc = useMemo(() => {\n if (!docId) return null;\n return new Y.Doc();\n }, [docId]);\n\n // Stable Awareness per ydoc\n const awareness = useMemo(() => {\n if (!ydoc) return null;\n return new Awareness(ydoc);\n }, [ydoc]);\n\n const [isLoading, setIsLoading] = useState(!!docId);\n const [isSynced, setIsSynced] = useState(false);\n const [activeUsers, setActiveUsers] = useState<CollabUser[]>([]);\n const [agentActive, setAgentActive] = useState(false);\n const [agentPresent, setAgentPresent] = useState(false);\n // Set when the initial state fetch returns 404/403 — stops the awareness\n // poll so we don't spam the console with errors against a doc that doesn't\n // exist or isn't accessible.\n const [docMissing, setDocMissing] = useState(false);\n const agentTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pollVersionRef = useRef(0);\n\n // Set local awareness state (user info for cursor labels)\n useEffect(() => {\n if (!awareness || !user) return;\n awareness.setLocalStateField(\"user\", {\n name: user.name,\n email: user.email,\n color: user.color,\n });\n }, [awareness, user?.name, user?.email, user?.color]);\n\n // Track active users from awareness changes\n useEffect(() => {\n if (!awareness) return;\n\n const updateUsers = () => {\n const users: CollabUser[] = [];\n let hasAgent = false;\n awareness.getStates().forEach((state, clientId) => {\n if (clientId === ydoc?.clientID) return; // Skip self\n if (state.user) {\n users.push(state.user as CollabUser);\n if ((state.user as CollabUser).email === \"agent@system\") {\n hasAgent = true;\n }\n }\n });\n setActiveUsers(dedupeCollabUsersByEmail(users));\n setAgentPresent(hasAgent);\n };\n\n awareness.on(\"change\", updateUsers);\n return () => {\n awareness.off(\"change\", updateUsers);\n };\n }, [awareness, ydoc]);\n\n // Clean up on unmount or docId change\n useEffect(() => {\n return () => {\n awareness?.destroy();\n ydoc?.destroy();\n };\n }, [ydoc, awareness]);\n\n // Fetch server state and apply to existing doc\n useEffect(() => {\n if (!ydoc || !docId) {\n setIsLoading(false);\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n setIsSynced(false);\n setDocMissing(false);\n\n fetch(`${baseUrl}/${docId}/state`)\n .then(async (res) => {\n if (cancelled) return;\n if (res.status === 404 || res.status === 403) {\n setDocMissing(true);\n setIsLoading(false);\n setIsSynced(true);\n return;\n }\n const data = (await res.json().catch(() => null)) as {\n state?: string;\n } | null;\n if (data?.state) {\n const binary = base64ToUint8Array(data.state);\n if (binary.length > 4) {\n Y.applyUpdate(ydoc, binary);\n }\n }\n setIsLoading(false);\n setIsSynced(true);\n })\n .catch(() => {\n if (cancelled) return;\n setIsLoading(false);\n setIsSynced(true);\n });\n\n return () => {\n cancelled = true;\n };\n }, [ydoc, docId, baseUrl]);\n\n // Send local updates to server\n useEffect(() => {\n if (!ydoc || !docId || docMissing) return;\n\n const handler = (update: Uint8Array, origin: unknown) => {\n if (origin === \"remote\") return;\n\n fetch(`${baseUrl}/${docId}/update`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n update: uint8ArrayToBase64(update),\n requestSource,\n }),\n });\n };\n\n ydoc.on(\"update\", handler);\n return () => {\n ydoc.off(\"update\", handler);\n };\n }, [ydoc, docId, baseUrl, requestSource, docMissing]);\n\n // Poll for remote doc updates + awareness sync\n useEffect(() => {\n if (!ydoc || !docId || docMissing) return;\n\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n async function poll() {\n if (stopped) return;\n try {\n // Poll for document updates\n const res = await fetch(\n agentNativePath(\n `/_agent-native/poll?since=${pollVersionRef.current}`,\n ),\n );\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n const data = await res.json();\n const { version, events } = data as {\n version: number;\n events: Array<{\n source: string;\n docId?: string;\n update?: string;\n requestSource?: string;\n }>;\n };\n\n for (const evt of events) {\n if (evt.source === \"collab\" && evt.docId === docId && evt.update) {\n if (requestSource && evt.requestSource === requestSource) continue;\n Y.applyUpdate(ydoc, base64ToUint8Array(evt.update), \"remote\");\n\n // Show agent presence indicator briefly\n if (evt.requestSource === \"agent\") {\n setAgentActive(true);\n if (agentTimerRef.current) clearTimeout(agentTimerRef.current);\n agentTimerRef.current = setTimeout(\n () => setAgentActive(false),\n 3000,\n );\n }\n }\n }\n\n pollVersionRef.current = version;\n\n // Sync awareness (cursor positions)\n if (awareness) {\n const localState = awareness.getLocalState();\n if (localState) {\n const awarenessRes = await fetch(`${baseUrl}/${docId}/awareness`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n clientId: ydoc.clientID,\n state: JSON.stringify(localState),\n }),\n });\n if (awarenessRes.ok) {\n const awarenessData = await awarenessRes.json();\n const remoteStates: RemoteAwarenessSnapshot[] = [];\n for (const remote of awarenessData.states || []) {\n try {\n const remoteState = JSON.parse(remote.state);\n remoteStates.push({\n clientId: Number(remote.clientId),\n state: remoteState,\n });\n } catch {\n // Invalid state — skip\n }\n }\n const changes = reconcileRemoteAwarenessStates(\n awareness.getStates() as Map<number, unknown>,\n ydoc.clientID,\n remoteStates,\n );\n if (\n changes.added.length ||\n changes.updated.length ||\n changes.removed.length\n ) {\n awareness.emit(\"change\", [changes, \"remote\"]);\n }\n }\n }\n }\n } catch {\n // Network error — retry next interval\n }\n if (!stopped) {\n timer = setTimeout(poll, pollInterval);\n }\n }\n\n poll();\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n };\n }, [\n ydoc,\n awareness,\n docId,\n pollInterval,\n requestSource,\n baseUrl,\n docMissing,\n ]);\n\n return {\n ydoc,\n awareness,\n isLoading,\n isSynced,\n activeUsers,\n agentActive,\n agentPresent,\n };\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/collab/client.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Client-side hook for collaborative document editing via Yjs.\n *\n * Creates a STABLE Y.Doc per docId that never changes identity. This allows\n * TipTap's Collaboration extension to bind once without editor recreation.\n * Server state is applied to the existing doc when it arrives.\n *\n * Also manages Yjs Awareness for cursor positions and user presence,\n * synced via polling to the server's awareness endpoint.\n */\n\nimport { useEffect, useRef, useState, useMemo } from \"react\";\nimport * as Y from \"yjs\";\nimport { Awareness } from \"y-protocols/awareness\";\nimport { agentNativePath } from \"../client/api-path.js\";\n\nexport interface CollabUser {\n name: string;\n email: string;\n color: string;\n}\n\nexport interface UseCollaborativeDocOptions {\n /** Document ID to collaborate on. Pass null to disable. */\n docId: string | null;\n /** Poll interval in ms. Default: 2000 */\n pollInterval?: number;\n /** Pause remote update/presence polling while the tab is hidden. Default: true */\n pauseWhenHidden?: boolean;\n /** Base URL for collab endpoints. Default: \"/_agent-native/collab\" */\n baseUrl?: string;\n /** Request source ID for jitter prevention (e.g., tab ID). */\n requestSource?: string;\n /** Current user info for cursor labels. */\n user?: CollabUser;\n}\n\nexport interface UseCollaborativeDocResult {\n /** The Yjs document instance. Stable per docId — never changes identity. */\n ydoc: Y.Doc | null;\n /** Yjs Awareness instance for cursor/presence sync. */\n awareness: Awareness | null;\n /** Whether the initial state is still loading from the server. */\n isLoading: boolean;\n /** Whether the doc is synced with the server. */\n isSynced: boolean;\n /** Active users on this document (from awareness). */\n activeUsers: CollabUser[];\n /** True briefly when the AI agent makes an edit (for presence indicator). */\n agentActive: boolean;\n /** True when the AI agent has an active awareness entry (durable presence). */\n agentPresent: boolean;\n}\n\n// Consistent color palette for user cursors\nconst CURSOR_COLORS = [\n \"#f87171\",\n \"#fb923c\",\n \"#fbbf24\",\n \"#a3e635\",\n \"#34d399\",\n \"#22d3ee\",\n \"#60a5fa\",\n \"#a78bfa\",\n \"#f472b6\",\n \"#e879f9\",\n];\n\n/** Hash a string to a consistent color from the palette. */\nexport function emailToColor(email: string): string {\n let hash = 0;\n for (let i = 0; i < email.length; i++) {\n hash = ((hash << 5) - hash + email.charCodeAt(i)) | 0;\n }\n return CURSOR_COLORS[Math.abs(hash) % CURSOR_COLORS.length];\n}\n\n/** Derive a display name from an email address. */\nexport function emailToName(email: string): string {\n const local = email.split(\"@\")[0] || email;\n return local.charAt(0).toUpperCase() + local.slice(1);\n}\n\nfunction normalizeCollabEmail(email: string): string {\n return email.trim().toLowerCase();\n}\n\nfunction isDocumentHidden(): boolean {\n return (\n typeof document !== \"undefined\" && document.visibilityState === \"hidden\"\n );\n}\n\nexport function dedupeCollabUsersByEmail(users: CollabUser[]): CollabUser[] {\n const byEmail = new Map<string, CollabUser>();\n for (const user of users) {\n const email = normalizeCollabEmail(user.email);\n if (!email || byEmail.has(email)) continue;\n byEmail.set(email, {\n name: user.name || emailToName(email),\n email,\n color: user.color || emailToColor(email),\n });\n }\n return Array.from(byEmail.values());\n}\n\nexport interface RemoteAwarenessSnapshot {\n clientId: number;\n state: unknown;\n}\n\nexport function reconcileRemoteAwarenessStates(\n states: Map<number, unknown>,\n localClientId: number,\n remoteStates: RemoteAwarenessSnapshot[],\n): { added: number[]; updated: number[]; removed: number[] } {\n const incoming = new Set<number>();\n const added: number[] = [];\n const updated: number[] = [];\n const removed: number[] = [];\n\n for (const remote of remoteStates) {\n if (\n !Number.isFinite(remote.clientId) ||\n remote.clientId === localClientId\n ) {\n continue;\n }\n incoming.add(remote.clientId);\n const hadState = states.has(remote.clientId);\n states.set(remote.clientId, remote.state);\n (hadState ? updated : added).push(remote.clientId);\n }\n\n for (const clientId of Array.from(states.keys())) {\n if (clientId === localClientId) continue;\n if (incoming.has(clientId)) continue;\n states.delete(clientId);\n removed.push(clientId);\n }\n\n return { added, updated, removed };\n}\n\n// Base64 helpers\nfunction uint8ArrayToBase64(arr: Uint8Array): string {\n let binary = \"\";\n for (let i = 0; i < arr.length; i++) {\n binary += String.fromCharCode(arr[i]);\n }\n return btoa(binary);\n}\n\nfunction base64ToUint8Array(b64: string): Uint8Array {\n const binary = atob(b64);\n const arr = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) {\n arr[i] = binary.charCodeAt(i);\n }\n return arr;\n}\n\nexport function useCollaborativeDoc(\n options: UseCollaborativeDocOptions,\n): UseCollaborativeDocResult {\n const {\n docId,\n pollInterval = 2000,\n pauseWhenHidden = true,\n baseUrl = agentNativePath(\"/_agent-native/collab\"),\n requestSource,\n user,\n } = options;\n\n // Stable Y.Doc per docId\n const ydoc = useMemo(() => {\n if (!docId) return null;\n return new Y.Doc();\n }, [docId]);\n\n // Stable Awareness per ydoc\n const awareness = useMemo(() => {\n if (!ydoc) return null;\n return new Awareness(ydoc);\n }, [ydoc]);\n\n const [isLoading, setIsLoading] = useState(!!docId);\n const [isSynced, setIsSynced] = useState(false);\n const [activeUsers, setActiveUsers] = useState<CollabUser[]>([]);\n const [agentActive, setAgentActive] = useState(false);\n const [agentPresent, setAgentPresent] = useState(false);\n // Set when the initial state fetch returns 404/403 — stops the awareness\n // poll so we don't spam the console with errors against a doc that doesn't\n // exist or isn't accessible.\n const [docMissing, setDocMissing] = useState(false);\n const agentTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n const pollVersionRef = useRef(0);\n\n // Set local awareness state (user info for cursor labels)\n useEffect(() => {\n if (!awareness || !user) return;\n awareness.setLocalStateField(\"user\", {\n name: user.name,\n email: user.email,\n color: user.color,\n });\n }, [awareness, user?.name, user?.email, user?.color]);\n\n // Track active users from awareness changes\n useEffect(() => {\n if (!awareness) return;\n\n const updateUsers = () => {\n const users: CollabUser[] = [];\n let hasAgent = false;\n awareness.getStates().forEach((state, clientId) => {\n if (clientId === ydoc?.clientID) return; // Skip self\n if (state.user) {\n users.push(state.user as CollabUser);\n if ((state.user as CollabUser).email === \"agent@system\") {\n hasAgent = true;\n }\n }\n });\n setActiveUsers(dedupeCollabUsersByEmail(users));\n setAgentPresent(hasAgent);\n };\n\n awareness.on(\"change\", updateUsers);\n return () => {\n awareness.off(\"change\", updateUsers);\n };\n }, [awareness, ydoc]);\n\n // Clean up on unmount or docId change\n useEffect(() => {\n return () => {\n awareness?.destroy();\n ydoc?.destroy();\n };\n }, [ydoc, awareness]);\n\n // Fetch server state and apply to existing doc\n useEffect(() => {\n if (!ydoc || !docId) {\n setIsLoading(false);\n return;\n }\n\n let cancelled = false;\n setIsLoading(true);\n setIsSynced(false);\n setDocMissing(false);\n\n fetch(`${baseUrl}/${docId}/state`)\n .then(async (res) => {\n if (cancelled) return;\n if (res.status === 404 || res.status === 403) {\n setDocMissing(true);\n setIsLoading(false);\n setIsSynced(true);\n return;\n }\n const data = (await res.json().catch(() => null)) as {\n state?: string;\n } | null;\n if (data?.state) {\n const binary = base64ToUint8Array(data.state);\n if (binary.length > 4) {\n Y.applyUpdate(ydoc, binary);\n }\n }\n setIsLoading(false);\n setIsSynced(true);\n })\n .catch(() => {\n if (cancelled) return;\n setIsLoading(false);\n setIsSynced(true);\n });\n\n return () => {\n cancelled = true;\n };\n }, [ydoc, docId, baseUrl]);\n\n // Send local updates to server\n useEffect(() => {\n if (!ydoc || !docId || docMissing) return;\n\n const handler = (update: Uint8Array, origin: unknown) => {\n if (origin === \"remote\") return;\n\n fetch(`${baseUrl}/${docId}/update`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n update: uint8ArrayToBase64(update),\n requestSource,\n }),\n });\n };\n\n ydoc.on(\"update\", handler);\n return () => {\n ydoc.off(\"update\", handler);\n };\n }, [ydoc, docId, baseUrl, requestSource, docMissing]);\n\n // Poll for remote doc updates + awareness sync\n useEffect(() => {\n if (!ydoc || !docId || docMissing) return;\n\n let stopped = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n function schedulePoll() {\n if (stopped) return;\n if (pauseWhenHidden && isDocumentHidden()) return;\n timer = setTimeout(poll, pollInterval);\n }\n\n async function poll() {\n if (stopped) return;\n try {\n // Poll for document updates\n const res = await fetch(\n agentNativePath(\n `/_agent-native/poll?since=${pollVersionRef.current}`,\n ),\n );\n if (!res.ok) throw new Error(\"HTTP \" + res.status);\n const data = await res.json();\n const { version, events } = data as {\n version: number;\n events: Array<{\n source: string;\n docId?: string;\n update?: string;\n requestSource?: string;\n }>;\n };\n\n for (const evt of events) {\n if (evt.source === \"collab\" && evt.docId === docId && evt.update) {\n if (requestSource && evt.requestSource === requestSource) continue;\n Y.applyUpdate(ydoc, base64ToUint8Array(evt.update), \"remote\");\n\n // Show agent presence indicator briefly\n if (evt.requestSource === \"agent\") {\n setAgentActive(true);\n if (agentTimerRef.current) clearTimeout(agentTimerRef.current);\n agentTimerRef.current = setTimeout(\n () => setAgentActive(false),\n 3000,\n );\n }\n }\n }\n\n pollVersionRef.current = version;\n\n // Sync awareness (cursor positions)\n if (awareness) {\n const localState = awareness.getLocalState();\n if (localState) {\n const awarenessRes = await fetch(`${baseUrl}/${docId}/awareness`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n clientId: ydoc.clientID,\n state: JSON.stringify(localState),\n }),\n });\n if (awarenessRes.ok) {\n const awarenessData = await awarenessRes.json();\n const remoteStates: RemoteAwarenessSnapshot[] = [];\n for (const remote of awarenessData.states || []) {\n try {\n const remoteState = JSON.parse(remote.state);\n remoteStates.push({\n clientId: Number(remote.clientId),\n state: remoteState,\n });\n } catch {\n // Invalid state — skip\n }\n }\n const changes = reconcileRemoteAwarenessStates(\n awareness.getStates() as Map<number, unknown>,\n ydoc.clientID,\n remoteStates,\n );\n if (\n changes.added.length ||\n changes.updated.length ||\n changes.removed.length\n ) {\n awareness.emit(\"change\", [changes, \"remote\"]);\n }\n }\n }\n }\n } catch {\n // Network error — retry next interval\n }\n schedulePoll();\n }\n\n function pollNow() {\n if (pauseWhenHidden && isDocumentHidden()) return;\n if (timer) {\n clearTimeout(timer);\n timer = null;\n }\n void poll();\n }\n\n function handleVisibilityChange() {\n if (document.visibilityState === \"visible\") {\n pollNow();\n } else if (pauseWhenHidden && timer) {\n clearTimeout(timer);\n timer = null;\n }\n }\n\n if (!pauseWhenHidden || !isDocumentHidden()) {\n void poll();\n }\n window.addEventListener(\"focus\", pollNow);\n document.addEventListener(\"visibilitychange\", handleVisibilityChange);\n\n return () => {\n stopped = true;\n if (timer) clearTimeout(timer);\n window.removeEventListener(\"focus\", pollNow);\n document.removeEventListener(\"visibilitychange\", handleVisibilityChange);\n };\n }, [\n ydoc,\n awareness,\n docId,\n pollInterval,\n pauseWhenHidden,\n requestSource,\n baseUrl,\n docMissing,\n ]);\n\n return {\n ydoc,\n awareness,\n isLoading,\n isSynced,\n activeUsers,\n agentActive,\n agentPresent,\n };\n}\n"]}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { createProductionAgentHandler, type ActionEntry, type ScriptEntry, type ProductionAgentOptions, type ActionTool, type ScriptTool, type AgentMessage, type AgentChatRequest, type AgentChatEvent, DEFAULT_MODEL, } from "./agent/index.js";
|
|
1
|
+
export { createProductionAgentHandler, type ActionEntry, type ScriptEntry, type ProductionAgentOptions, type ActionTool, type ScriptTool, type AgentMessage, type AgentChatRequest, type AgentChatEvent, type AgentChatAttachment, DEFAULT_MODEL, } from "./agent/index.js";
|
|
2
2
|
export { defineAction, AgentActionStopError, isAgentActionStopError, type ActionHttpConfig, type AgentActionStopOptions, } from "./action.js";
|
|
3
3
|
export { createDevScriptRegistry } from "./scripts/dev/index.js";
|
|
4
4
|
export { createAgentChatPlugin, defaultAgentChatPlugin, type AgentChatPluginOptions, } from "./server/agent-chat-plugin.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,4BAA4B,EAC5B,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,EAAE,EACF,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,SAAS,EACT,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,2BAA2B,EAC3B,sCAAsC,EACtC,6BAA6B,EAC7B,4BAA4B,EAC5B,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,SAAS,EACT,OAAO,EACP,SAAS,EACT,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,IAAI,GACL,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,oBAAoB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA,OAAO,EACL,4BAA4B,EAC5B,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,sBAAsB,EAC3B,KAAK,UAAU,EACf,KAAK,UAAU,EACf,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACnB,KAAK,mBAAmB,EACxB,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,EACtB,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,EACtB,KAAK,sBAAsB,GAC5B,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,UAAU,EACV,KAAK,mBAAmB,EACxB,KAAK,iBAAiB,EACtB,KAAK,WAAW,EAChB,KAAK,WAAW,GACjB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,EAAE,EACF,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EACpB,KAAK,gBAAgB,EACrB,KAAK,uBAAuB,EAC5B,KAAK,sBAAsB,EAC3B,KAAK,wBAAwB,EAC7B,KAAK,yBAAyB,EAC9B,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,SAAS,EACT,KAAK,oBAAoB,EACzB,KAAK,iBAAiB,GACvB,MAAM,mBAAmB,CAAC;AAG3B,OAAO,EACL,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,2BAA2B,EAC3B,sCAAsC,EACtC,6BAA6B,EAC7B,4BAA4B,EAC5B,iBAAiB,EACjB,KAAK,WAAW,EAChB,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACrB,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,WAAW,EAChB,KAAK,gBAAgB,GACtB,MAAM,kBAAkB,CAAC;AAG1B,OAAO,EACL,SAAS,EACT,OAAO,EACP,SAAS,EACT,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,IAAI,GACL,MAAM,oBAAoB,CAAC;AAK5B,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,eAAe,EACf,KAAK,gBAAgB,EACrB,KAAK,WAAW,EAChB,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,SAAS,GACf,MAAM,oBAAoB,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,+CAA+C;AAE/C,0BAA0B;AAC1B,OAAO,EACL,4BAA4B,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,mCAAmC;AACnC,+CAA+C;AAE/C,0BAA0B;AAC1B,OAAO,EACL,4BAA4B,EAU5B,aAAa,GACd,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,sBAAsB,GAGvB,MAAM,aAAa,CAAC;AACrB,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EACL,qBAAqB,EACrB,sBAAsB,GAEvB,MAAM,+BAA+B,CAAC;AAEvC,SAAS;AACT,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,aAAa,EACb,UAAU,GAKX,MAAM,mBAAmB,CAAC;AAE3B,SAAS;AACT,OAAO,EACL,eAAe,EACf,sBAAsB,EACtB,UAAU,EACV,kBAAkB,EAClB,kBAAkB,EAClB,SAAS,EACT,cAAc,EACd,EAAE,EACF,cAAc,EACd,UAAU,EACV,kBAAkB,EAClB,oBAAoB,EAMpB,cAAc,EACd,iBAAiB,GAClB,MAAM,mBAAmB,CAAC;AAE3B,sBAAsB;AACtB,OAAO,EACL,SAAS,GAGV,MAAM,mBAAmB,CAAC;AAE3B,uBAAuB;AACvB,OAAO,EACL,WAAW,EACX,eAAe,EACf,iBAAiB,EACjB,aAAa,EACb,qBAAqB,EACrB,2BAA2B,EAC3B,sCAAsC,EACtC,6BAA6B,EAC7B,4BAA4B,EAC5B,iBAAiB,GAQlB,MAAM,kBAAkB,CAAC;AAE1B,UAAU;AACV,OAAO,EACL,SAAS,EACT,OAAO,EACP,SAAS,EACT,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,SAAS,EACT,IAAI,GACL,MAAM,oBAAoB,CAAC;AAE5B,4EAA4E;AAC5E,wEAAwE;AACxE,mCAAmC;AACnC,OAAO,EACL,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,eAAe,GAMhB,MAAM,oBAAoB,CAAC","sourcesContent":["// Framework for agent-native apps.\n// Import everything from \"@agent-native/core\".\n\n// Agent (production mode)\nexport {\n createProductionAgentHandler,\n type ActionEntry,\n type ScriptEntry,\n type ProductionAgentOptions,\n type ActionTool,\n type ScriptTool,\n type AgentMessage,\n type AgentChatRequest,\n type AgentChatEvent,\n type AgentChatAttachment,\n DEFAULT_MODEL,\n} from \"./agent/index.js\";\nexport {\n defineAction,\n AgentActionStopError,\n isAgentActionStopError,\n type ActionHttpConfig,\n type AgentActionStopOptions,\n} from \"./action.js\";\nexport { createDevScriptRegistry } from \"./scripts/dev/index.js\";\nexport {\n createAgentChatPlugin,\n defaultAgentChatPlugin,\n type AgentChatPluginOptions,\n} from \"./server/agent-chat-plugin.js\";\n\n// Server\nexport {\n createServer,\n createSSEHandler,\n defineNitroPlugin,\n autoMountAuth,\n getSession,\n type CreateServerOptions,\n type SSEHandlerOptions,\n type AuthSession,\n type AuthOptions,\n} from \"./server/index.js\";\n\n// Client\nexport {\n sendToAgentChat,\n useAgentChatGenerating,\n useDevMode,\n useSendToAgentChat,\n CodeRequiredDialog,\n useDbSync,\n useFileWatcher,\n cn,\n ApiKeySettings,\n useSession,\n useProductionAgent,\n ProductionAgentPanel,\n type AgentChatMessage,\n type CodeRequiredDialogProps,\n type ProductionAgentMessage,\n type UseProductionAgentResult,\n type ProductionAgentPanelProps,\n useActionQuery,\n useActionMutation,\n} from \"./client/index.js\";\n\n// Shared (isomorphic)\nexport {\n agentChat,\n type AgentChatCallOptions,\n type AgentChatResponse,\n} from \"./shared/index.js\";\n\n// Token usage tracking\nexport {\n recordUsage,\n getUsageSummary,\n getUserUsageCents,\n calculateCost,\n usageBillingForEngine,\n builderCreditsFromCostCents,\n BUILDER_AGENT_CREDIT_MARGIN_MULTIPLIER,\n BUILDER_AGENT_CREDITS_PER_USD,\n BUILDER_CREDIT_USAGE_BILLING,\n USD_USAGE_BILLING,\n type UsageRecord,\n type UsageSummary,\n type UsageBillingMode,\n type UsageBillingUnit,\n type UsageBucket,\n type DailyBucket,\n type UsageRecentEntry,\n} from \"./usage/store.js\";\n\n// Scripts\nexport {\n runScript,\n loadEnv,\n parseArgs,\n camelCaseArgs,\n isValidPath,\n isValidProjectPath,\n ensureDir,\n fail,\n} from \"./scripts/index.js\";\n\n// Secrets registry — import from \"@agent-native/core/secrets\" when possible\n// (the subpath keeps the top-level entry point lean), but re-export the\n// public API here for convenience.\nexport {\n registerRequiredSecret,\n listRequiredSecrets,\n getRequiredSecret,\n readAppSecret,\n writeAppSecret,\n deleteAppSecret,\n type RegisteredSecret,\n type SecretScope,\n type SecretKind,\n type SecretValidator,\n type SecretRef,\n} from \"./secrets/index.js\";\n"]}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type ActionEntry } from "../agent/production-agent.js";
|
|
2
|
-
import type { AgentChatEvent, MentionProvider } from "../agent/types.js";
|
|
2
|
+
import type { AgentChatAttachment, AgentChatEvent, AgentChatReference, MentionProvider } from "../agent/types.js";
|
|
3
3
|
import { McpClientManager } from "../mcp-client/index.js";
|
|
4
4
|
import { type A2AArtifactResponseOptions, type A2AToolResultSummary } from "../a2a/artifact-response.js";
|
|
5
5
|
export declare function assembleA2AFinalResponse(events: readonly AgentChatEvent[], toolResults: readonly A2AToolResultSummary[], options?: A2AArtifactResponseOptions & {
|
|
@@ -89,6 +89,30 @@ export interface AgentChatPluginOptions {
|
|
|
89
89
|
* real data-source tool calls for analytics requests.
|
|
90
90
|
*/
|
|
91
91
|
finalResponseGuard?: import("../agent/production-agent.js").AgentLoopFinalResponseGuard;
|
|
92
|
+
/**
|
|
93
|
+
* Optional per-template request normalizer. Runs after authentication and
|
|
94
|
+
* before the model sees the message, so apps can translate chat attachments
|
|
95
|
+
* into template-native file handles while preserving the user's visible text.
|
|
96
|
+
*/
|
|
97
|
+
prepareRequest?: (details: {
|
|
98
|
+
event: any;
|
|
99
|
+
ownerEmail: string | null;
|
|
100
|
+
message: string;
|
|
101
|
+
displayMessage?: string;
|
|
102
|
+
attachments: AgentChatAttachment[];
|
|
103
|
+
references: AgentChatReference[];
|
|
104
|
+
threadId?: string;
|
|
105
|
+
internalContinuation?: boolean;
|
|
106
|
+
mode: "act" | "plan";
|
|
107
|
+
}) => void | {
|
|
108
|
+
message?: string;
|
|
109
|
+
displayMessage?: string;
|
|
110
|
+
attachments?: AgentChatAttachment[];
|
|
111
|
+
} | Promise<void | {
|
|
112
|
+
message?: string;
|
|
113
|
+
displayMessage?: string;
|
|
114
|
+
attachments?: AgentChatAttachment[];
|
|
115
|
+
}>;
|
|
92
116
|
/**
|
|
93
117
|
* Use ONLY the template's `systemPrompt` and the actions list — skip the
|
|
94
118
|
* framework prompt wrapper, resource loading (AGENTS.md/LEARNINGS.md/
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent-chat-plugin.d.ts","sourceRoot":"","sources":["../../src/server/agent-chat-plugin.ts"],"names":[],"mappings":"AAaA,OAAO,EAUL,KAAK,WAAW,EACjB,MAAM,8BAA8B,CAAC;AAStC,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"agent-chat-plugin.d.ts","sourceRoot":"","sources":["../../src/server/agent-chat-plugin.ts"],"names":[],"mappings":"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"}
|
|
@@ -3005,6 +3005,7 @@ export function createAgentChatPlugin(options) {
|
|
|
3005
3005
|
apiKey: options?.apiKey,
|
|
3006
3006
|
runSoftTimeoutMs: options?.runSoftTimeoutMs,
|
|
3007
3007
|
finalResponseGuard: options?.finalResponseGuard,
|
|
3008
|
+
prepareRequest: options?.prepareRequest,
|
|
3008
3009
|
skipFilesContext: leanPrompt,
|
|
3009
3010
|
onEngineResolved: (engine, model) => {
|
|
3010
3011
|
const runCtx = ensureRequestRunContext();
|
|
@@ -3042,6 +3043,7 @@ export function createAgentChatPlugin(options) {
|
|
|
3042
3043
|
apiKey: options?.apiKey,
|
|
3043
3044
|
runSoftTimeoutMs: options?.runSoftTimeoutMs,
|
|
3044
3045
|
finalResponseGuard: options?.finalResponseGuard,
|
|
3046
|
+
prepareRequest: options?.prepareRequest,
|
|
3045
3047
|
skipFilesContext: true,
|
|
3046
3048
|
onEngineResolved: (engine, model) => {
|
|
3047
3049
|
const runCtx = ensureRequestRunContext();
|
|
@@ -3127,6 +3129,7 @@ export function createAgentChatPlugin(options) {
|
|
|
3127
3129
|
apiKey: options?.apiKey,
|
|
3128
3130
|
runSoftTimeoutMs: options?.runSoftTimeoutMs,
|
|
3129
3131
|
finalResponseGuard: options?.finalResponseGuard,
|
|
3132
|
+
prepareRequest: options?.prepareRequest,
|
|
3130
3133
|
skipFilesContext: leanPrompt,
|
|
3131
3134
|
onEngineResolved: (engine, model) => {
|
|
3132
3135
|
const runCtx = ensureRequestRunContext();
|