@agimon-ai/po 0.0.0-alpha.50 → 0.0.0-alpha.51
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/catalog/index.json +54 -54
- package/dist/src/builders/server/nativePush.cjs +33 -3
- package/dist/src/builders/server/nativePush.cjs.map +1 -1
- package/dist/src/builders/server/nativePush.mjs +33 -3
- package/dist/src/builders/server/nativePush.mjs.map +1 -1
- package/dist/src/builders/server/runtime.cjs +5 -2
- package/dist/src/builders/server/runtime.cjs.map +1 -1
- package/dist/src/builders/server/runtime.mjs +5 -2
- package/dist/src/builders/server/runtime.mjs.map +1 -1
- package/dist/src/builders/server/sandboxRouter.cjs +1 -1
- package/dist/src/builders/server/sandboxRouter.cjs.map +1 -1
- package/dist/src/builders/server/sandboxRouter.mjs +1 -1
- package/dist/src/builders/server/sandboxRouter.mjs.map +1 -1
- package/package.json +21 -21
package/dist/catalog/index.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"version": 1,
|
|
3
3
|
"packages": {
|
|
4
4
|
"@agimon-ai/po": {
|
|
5
|
-
"version": "0.0.0-alpha.
|
|
5
|
+
"version": "0.0.0-alpha.51",
|
|
6
6
|
"dependencies": [
|
|
7
7
|
"@agimon-ai/po-approval",
|
|
8
8
|
"@agimon-ai/po-artifact",
|
|
@@ -24,14 +24,14 @@
|
|
|
24
24
|
]
|
|
25
25
|
},
|
|
26
26
|
"@agimon-ai/po-approval": {
|
|
27
|
-
"version": "0.0.0-alpha.
|
|
27
|
+
"version": "0.0.0-alpha.50",
|
|
28
28
|
"dependencies": [
|
|
29
29
|
"@agimon-ai/po-core",
|
|
30
30
|
"@agimon-ai/po-web-components"
|
|
31
31
|
]
|
|
32
32
|
},
|
|
33
33
|
"@agimon-ai/po-artifact": {
|
|
34
|
-
"version": "0.0.0-alpha.
|
|
34
|
+
"version": "0.0.0-alpha.49",
|
|
35
35
|
"dependencies": [
|
|
36
36
|
"@agimon-ai/po-core",
|
|
37
37
|
"@agimon-ai/po-web-components",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
]
|
|
40
40
|
},
|
|
41
41
|
"@agimon-ai/po-author": {
|
|
42
|
-
"version": "0.0.0-alpha.
|
|
42
|
+
"version": "0.0.0-alpha.50",
|
|
43
43
|
"dependencies": [
|
|
44
44
|
"@agimon-ai/po-artifact",
|
|
45
45
|
"@agimon-ai/po-core",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
]
|
|
50
50
|
},
|
|
51
51
|
"@agimon-ai/po-autocompact": {
|
|
52
|
-
"version": "0.0.0-alpha.
|
|
52
|
+
"version": "0.0.0-alpha.50",
|
|
53
53
|
"dependencies": [
|
|
54
54
|
"@agimon-ai/po-artifact",
|
|
55
55
|
"@agimon-ai/po-config",
|
|
@@ -58,24 +58,24 @@
|
|
|
58
58
|
]
|
|
59
59
|
},
|
|
60
60
|
"@agimon-ai/po-autostop": {
|
|
61
|
-
"version": "0.0.0-alpha.
|
|
61
|
+
"version": "0.0.0-alpha.50",
|
|
62
62
|
"dependencies": [
|
|
63
63
|
"@agimon-ai/po-core"
|
|
64
64
|
]
|
|
65
65
|
},
|
|
66
66
|
"@agimon-ai/po-browse": {
|
|
67
|
-
"version": "0.0.1-alpha.
|
|
67
|
+
"version": "0.0.1-alpha.48",
|
|
68
68
|
"dependencies": [
|
|
69
69
|
"@agimon-ai/po-core",
|
|
70
70
|
"@agimon-ai/po-web-components"
|
|
71
71
|
]
|
|
72
72
|
},
|
|
73
73
|
"@agimon-ai/po-build": {
|
|
74
|
-
"version": "0.0.0-alpha.
|
|
74
|
+
"version": "0.0.0-alpha.50",
|
|
75
75
|
"dependencies": []
|
|
76
76
|
},
|
|
77
77
|
"@agimon-ai/po-cache": {
|
|
78
|
-
"version": "0.0.0-alpha.
|
|
78
|
+
"version": "0.0.0-alpha.50",
|
|
79
79
|
"dependencies": [
|
|
80
80
|
"@agimon-ai/po-config",
|
|
81
81
|
"@agimon-ai/po-core",
|
|
@@ -83,7 +83,7 @@
|
|
|
83
83
|
]
|
|
84
84
|
},
|
|
85
85
|
"@agimon-ai/po-calendar": {
|
|
86
|
-
"version": "0.0.1-alpha.
|
|
86
|
+
"version": "0.0.1-alpha.9",
|
|
87
87
|
"dependencies": [
|
|
88
88
|
"@agimon-ai/po-config",
|
|
89
89
|
"@agimon-ai/po-core",
|
|
@@ -93,11 +93,11 @@
|
|
|
93
93
|
]
|
|
94
94
|
},
|
|
95
95
|
"@agimon-ai/po-claude-bridge": {
|
|
96
|
-
"version": "0.1.1-alpha.
|
|
96
|
+
"version": "0.1.1-alpha.30",
|
|
97
97
|
"dependencies": []
|
|
98
98
|
},
|
|
99
99
|
"@agimon-ai/po-codemode": {
|
|
100
|
-
"version": "0.0.1-alpha.
|
|
100
|
+
"version": "0.0.1-alpha.23",
|
|
101
101
|
"dependencies": [
|
|
102
102
|
"@agimon-ai/po-config",
|
|
103
103
|
"@agimon-ai/po-core",
|
|
@@ -105,7 +105,7 @@
|
|
|
105
105
|
]
|
|
106
106
|
},
|
|
107
107
|
"@agimon-ai/po-computer-use": {
|
|
108
|
-
"version": "0.0.0-alpha.
|
|
108
|
+
"version": "0.0.0-alpha.50",
|
|
109
109
|
"dependencies": [
|
|
110
110
|
"@agimon-ai/po-config",
|
|
111
111
|
"@agimon-ai/po-core",
|
|
@@ -115,20 +115,20 @@
|
|
|
115
115
|
]
|
|
116
116
|
},
|
|
117
117
|
"@agimon-ai/po-config": {
|
|
118
|
-
"version": "0.0.0-alpha.
|
|
118
|
+
"version": "0.0.0-alpha.50",
|
|
119
119
|
"dependencies": [
|
|
120
120
|
"@agimon-ai/po-core",
|
|
121
121
|
"@agimon-ai/po-web-components"
|
|
122
122
|
]
|
|
123
123
|
},
|
|
124
124
|
"@agimon-ai/po-core": {
|
|
125
|
-
"version": "0.0.0-alpha.
|
|
125
|
+
"version": "0.0.0-alpha.50",
|
|
126
126
|
"dependencies": [
|
|
127
127
|
"@agimon-ai/po-web-security"
|
|
128
128
|
]
|
|
129
129
|
},
|
|
130
130
|
"@agimon-ai/po-domain": {
|
|
131
|
-
"version": "0.0.0-alpha.
|
|
131
|
+
"version": "0.0.0-alpha.50",
|
|
132
132
|
"dependencies": [
|
|
133
133
|
"@agimon-ai/po-config",
|
|
134
134
|
"@agimon-ai/po-core",
|
|
@@ -136,7 +136,7 @@
|
|
|
136
136
|
]
|
|
137
137
|
},
|
|
138
138
|
"@agimon-ai/po-edit": {
|
|
139
|
-
"version": "0.0.0-alpha.
|
|
139
|
+
"version": "0.0.0-alpha.50",
|
|
140
140
|
"dependencies": [
|
|
141
141
|
"@agimon-ai/po-core",
|
|
142
142
|
"@agimon-ai/po-hashline",
|
|
@@ -145,7 +145,7 @@
|
|
|
145
145
|
]
|
|
146
146
|
},
|
|
147
147
|
"@agimon-ai/po-file-edit": {
|
|
148
|
-
"version": "0.0.0-alpha.
|
|
148
|
+
"version": "0.0.0-alpha.50",
|
|
149
149
|
"dependencies": [
|
|
150
150
|
"@agimon-ai/po-config",
|
|
151
151
|
"@agimon-ai/po-core",
|
|
@@ -155,7 +155,7 @@
|
|
|
155
155
|
]
|
|
156
156
|
},
|
|
157
157
|
"@agimon-ai/po-git": {
|
|
158
|
-
"version": "0.0.0-alpha.
|
|
158
|
+
"version": "0.0.0-alpha.50",
|
|
159
159
|
"dependencies": [
|
|
160
160
|
"@agimon-ai/po-core",
|
|
161
161
|
"@agimon-ai/po-session",
|
|
@@ -164,7 +164,7 @@
|
|
|
164
164
|
]
|
|
165
165
|
},
|
|
166
166
|
"@agimon-ai/po-goal": {
|
|
167
|
-
"version": "0.0.0-alpha.
|
|
167
|
+
"version": "0.0.0-alpha.50",
|
|
168
168
|
"dependencies": [
|
|
169
169
|
"@agimon-ai/po-core",
|
|
170
170
|
"@agimon-ai/po-minor-mode",
|
|
@@ -173,7 +173,7 @@
|
|
|
173
173
|
]
|
|
174
174
|
},
|
|
175
175
|
"@agimon-ai/po-grep": {
|
|
176
|
-
"version": "0.0.0-alpha.
|
|
176
|
+
"version": "0.0.0-alpha.50",
|
|
177
177
|
"dependencies": [
|
|
178
178
|
"@agimon-ai/po-core",
|
|
179
179
|
"@agimon-ai/po-hashline",
|
|
@@ -182,11 +182,11 @@
|
|
|
182
182
|
]
|
|
183
183
|
},
|
|
184
184
|
"@agimon-ai/po-hashline": {
|
|
185
|
-
"version": "0.0.0-alpha.
|
|
185
|
+
"version": "0.0.0-alpha.50",
|
|
186
186
|
"dependencies": []
|
|
187
187
|
},
|
|
188
188
|
"@agimon-ai/po-help": {
|
|
189
|
-
"version": "0.0.0-alpha.
|
|
189
|
+
"version": "0.0.0-alpha.50",
|
|
190
190
|
"dependencies": [
|
|
191
191
|
"@agimon-ai/po-core",
|
|
192
192
|
"@agimon-ai/po-minor-mode",
|
|
@@ -194,7 +194,7 @@
|
|
|
194
194
|
]
|
|
195
195
|
},
|
|
196
196
|
"@agimon-ai/po-image-gen": {
|
|
197
|
-
"version": "0.0.0-alpha.
|
|
197
|
+
"version": "0.0.0-alpha.49",
|
|
198
198
|
"dependencies": [
|
|
199
199
|
"@agimon-ai/po-core",
|
|
200
200
|
"@agimon-ai/po-web-components",
|
|
@@ -202,7 +202,7 @@
|
|
|
202
202
|
]
|
|
203
203
|
},
|
|
204
204
|
"@agimon-ai/po-log": {
|
|
205
|
-
"version": "0.0.0-alpha.
|
|
205
|
+
"version": "0.0.0-alpha.50",
|
|
206
206
|
"dependencies": [
|
|
207
207
|
"@agimon-ai/po-core",
|
|
208
208
|
"@agimon-ai/po-web-components",
|
|
@@ -210,7 +210,7 @@
|
|
|
210
210
|
]
|
|
211
211
|
},
|
|
212
212
|
"@agimon-ai/po-major-mode": {
|
|
213
|
-
"version": "0.0.0-alpha.
|
|
213
|
+
"version": "0.0.0-alpha.50",
|
|
214
214
|
"dependencies": [
|
|
215
215
|
"@agimon-ai/po-config",
|
|
216
216
|
"@agimon-ai/po-core",
|
|
@@ -218,7 +218,7 @@
|
|
|
218
218
|
]
|
|
219
219
|
},
|
|
220
220
|
"@agimon-ai/po-mcp": {
|
|
221
|
-
"version": "0.0.0-alpha.
|
|
221
|
+
"version": "0.0.0-alpha.50",
|
|
222
222
|
"dependencies": [
|
|
223
223
|
"@agimon-ai/po-config",
|
|
224
224
|
"@agimon-ai/po-core",
|
|
@@ -228,36 +228,36 @@
|
|
|
228
228
|
]
|
|
229
229
|
},
|
|
230
230
|
"@agimon-ai/po-mcp-proxy": {
|
|
231
|
-
"version": "0.0.1-alpha.
|
|
231
|
+
"version": "0.0.1-alpha.29",
|
|
232
232
|
"dependencies": []
|
|
233
233
|
},
|
|
234
234
|
"@agimon-ai/po-minor-mode": {
|
|
235
|
-
"version": "0.0.0-alpha.
|
|
235
|
+
"version": "0.0.0-alpha.50",
|
|
236
236
|
"dependencies": [
|
|
237
237
|
"@agimon-ai/po-core"
|
|
238
238
|
]
|
|
239
239
|
},
|
|
240
240
|
"@agimon-ai/po-model-guidance": {
|
|
241
|
-
"version": "0.0.0-alpha.
|
|
241
|
+
"version": "0.0.0-alpha.50",
|
|
242
242
|
"dependencies": [
|
|
243
243
|
"@agimon-ai/po-config",
|
|
244
244
|
"@agimon-ai/po-core"
|
|
245
245
|
]
|
|
246
246
|
},
|
|
247
247
|
"@agimon-ai/po-native-components": {
|
|
248
|
-
"version": "0.0.0-alpha.
|
|
248
|
+
"version": "0.0.0-alpha.50",
|
|
249
249
|
"dependencies": [
|
|
250
250
|
"@agimon-ai/po-web-components"
|
|
251
251
|
]
|
|
252
252
|
},
|
|
253
253
|
"@agimon-ai/po-notification": {
|
|
254
|
-
"version": "0.0.0-alpha.
|
|
254
|
+
"version": "0.0.0-alpha.50",
|
|
255
255
|
"dependencies": [
|
|
256
256
|
"@agimon-ai/po-core"
|
|
257
257
|
]
|
|
258
258
|
},
|
|
259
259
|
"@agimon-ai/po-plan": {
|
|
260
|
-
"version": "0.0.0-alpha.
|
|
260
|
+
"version": "0.0.0-alpha.50",
|
|
261
261
|
"dependencies": [
|
|
262
262
|
"@agimon-ai/po-config",
|
|
263
263
|
"@agimon-ai/po-core",
|
|
@@ -267,7 +267,7 @@
|
|
|
267
267
|
]
|
|
268
268
|
},
|
|
269
269
|
"@agimon-ai/po-profile": {
|
|
270
|
-
"version": "0.0.0-alpha.
|
|
270
|
+
"version": "0.0.0-alpha.50",
|
|
271
271
|
"dependencies": [
|
|
272
272
|
"@agimon-ai/po-config",
|
|
273
273
|
"@agimon-ai/po-core",
|
|
@@ -275,7 +275,7 @@
|
|
|
275
275
|
]
|
|
276
276
|
},
|
|
277
277
|
"@agimon-ai/po-prompt": {
|
|
278
|
-
"version": "0.0.0-alpha.
|
|
278
|
+
"version": "0.0.0-alpha.50",
|
|
279
279
|
"dependencies": [
|
|
280
280
|
"@agimon-ai/po-core",
|
|
281
281
|
"@agimon-ai/po-web-components",
|
|
@@ -283,7 +283,7 @@
|
|
|
283
283
|
]
|
|
284
284
|
},
|
|
285
285
|
"@agimon-ai/po-read": {
|
|
286
|
-
"version": "0.0.0-alpha.
|
|
286
|
+
"version": "0.0.0-alpha.50",
|
|
287
287
|
"dependencies": [
|
|
288
288
|
"@agimon-ai/po-config",
|
|
289
289
|
"@agimon-ai/po-core",
|
|
@@ -293,7 +293,7 @@
|
|
|
293
293
|
]
|
|
294
294
|
},
|
|
295
295
|
"@agimon-ai/po-runner": {
|
|
296
|
-
"version": "0.0.0-alpha.
|
|
296
|
+
"version": "0.0.0-alpha.50",
|
|
297
297
|
"dependencies": [
|
|
298
298
|
"@agimon-ai/po-core",
|
|
299
299
|
"@agimon-ai/po-ui",
|
|
@@ -302,13 +302,13 @@
|
|
|
302
302
|
]
|
|
303
303
|
},
|
|
304
304
|
"@agimon-ai/po-sandbox": {
|
|
305
|
-
"version": "0.0.0-alpha.
|
|
305
|
+
"version": "0.0.0-alpha.50",
|
|
306
306
|
"dependencies": [
|
|
307
307
|
"@agimon-ai/po-core"
|
|
308
308
|
]
|
|
309
309
|
},
|
|
310
310
|
"@agimon-ai/po-session": {
|
|
311
|
-
"version": "0.0.0-alpha.
|
|
311
|
+
"version": "0.0.0-alpha.50",
|
|
312
312
|
"dependencies": [
|
|
313
313
|
"@agimon-ai/po-config",
|
|
314
314
|
"@agimon-ai/po-core",
|
|
@@ -316,7 +316,7 @@
|
|
|
316
316
|
]
|
|
317
317
|
},
|
|
318
318
|
"@agimon-ai/po-skill": {
|
|
319
|
-
"version": "0.0.0-alpha.
|
|
319
|
+
"version": "0.0.0-alpha.50",
|
|
320
320
|
"dependencies": [
|
|
321
321
|
"@agimon-ai/po-config",
|
|
322
322
|
"@agimon-ai/po-core",
|
|
@@ -325,7 +325,7 @@
|
|
|
325
325
|
]
|
|
326
326
|
},
|
|
327
327
|
"@agimon-ai/po-style-system": {
|
|
328
|
-
"version": "0.0.0-alpha.
|
|
328
|
+
"version": "0.0.0-alpha.50",
|
|
329
329
|
"dependencies": [
|
|
330
330
|
"@agimon-ai/po-core",
|
|
331
331
|
"@agimon-ai/po-web-components",
|
|
@@ -333,7 +333,7 @@
|
|
|
333
333
|
]
|
|
334
334
|
},
|
|
335
335
|
"@agimon-ai/po-task": {
|
|
336
|
-
"version": "0.0.0-alpha.
|
|
336
|
+
"version": "0.0.0-alpha.50",
|
|
337
337
|
"dependencies": [
|
|
338
338
|
"@agimon-ai/po-core",
|
|
339
339
|
"@agimon-ai/po-ui",
|
|
@@ -341,7 +341,7 @@
|
|
|
341
341
|
]
|
|
342
342
|
},
|
|
343
343
|
"@agimon-ai/po-team": {
|
|
344
|
-
"version": "0.0.0-alpha.
|
|
344
|
+
"version": "0.0.0-alpha.50",
|
|
345
345
|
"dependencies": [
|
|
346
346
|
"@agimon-ai/po-cache",
|
|
347
347
|
"@agimon-ai/po-config",
|
|
@@ -353,7 +353,7 @@
|
|
|
353
353
|
]
|
|
354
354
|
},
|
|
355
355
|
"@agimon-ai/po-template-advanced": {
|
|
356
|
-
"version": "0.0.0-alpha.
|
|
356
|
+
"version": "0.0.0-alpha.50",
|
|
357
357
|
"dependencies": [
|
|
358
358
|
"@agimon-ai/po-core",
|
|
359
359
|
"@agimon-ai/po-web-components",
|
|
@@ -361,7 +361,7 @@
|
|
|
361
361
|
]
|
|
362
362
|
},
|
|
363
363
|
"@agimon-ai/po-template-elegant": {
|
|
364
|
-
"version": "0.0.0-alpha.
|
|
364
|
+
"version": "0.0.0-alpha.50",
|
|
365
365
|
"dependencies": [
|
|
366
366
|
"@agimon-ai/po-core",
|
|
367
367
|
"@agimon-ai/po-web-components",
|
|
@@ -369,7 +369,7 @@
|
|
|
369
369
|
]
|
|
370
370
|
},
|
|
371
371
|
"@agimon-ai/po-ui": {
|
|
372
|
-
"version": "0.0.0-alpha.
|
|
372
|
+
"version": "0.0.0-alpha.50",
|
|
373
373
|
"dependencies": [
|
|
374
374
|
"@agimon-ai/po-core",
|
|
375
375
|
"@agimon-ai/po-hashline",
|
|
@@ -378,7 +378,7 @@
|
|
|
378
378
|
]
|
|
379
379
|
},
|
|
380
380
|
"@agimon-ai/po-user-feedback": {
|
|
381
|
-
"version": "0.0.0-alpha.
|
|
381
|
+
"version": "0.0.0-alpha.50",
|
|
382
382
|
"dependencies": [
|
|
383
383
|
"@agimon-ai/po-core",
|
|
384
384
|
"@agimon-ai/po-minor-mode",
|
|
@@ -387,7 +387,7 @@
|
|
|
387
387
|
]
|
|
388
388
|
},
|
|
389
389
|
"@agimon-ai/po-vibe-lint": {
|
|
390
|
-
"version": "0.0.1-alpha.
|
|
390
|
+
"version": "0.0.1-alpha.19",
|
|
391
391
|
"dependencies": [
|
|
392
392
|
"@agimon-ai/po-config",
|
|
393
393
|
"@agimon-ai/po-core",
|
|
@@ -397,7 +397,7 @@
|
|
|
397
397
|
]
|
|
398
398
|
},
|
|
399
399
|
"@agimon-ai/po-voice": {
|
|
400
|
-
"version": "0.0.0-alpha.
|
|
400
|
+
"version": "0.0.0-alpha.50",
|
|
401
401
|
"dependencies": [
|
|
402
402
|
"@agimon-ai/po-config",
|
|
403
403
|
"@agimon-ai/po-core",
|
|
@@ -409,11 +409,11 @@
|
|
|
409
409
|
]
|
|
410
410
|
},
|
|
411
411
|
"@agimon-ai/po-web-components": {
|
|
412
|
-
"version": "0.0.0-alpha.
|
|
412
|
+
"version": "0.0.0-alpha.50",
|
|
413
413
|
"dependencies": []
|
|
414
414
|
},
|
|
415
415
|
"@agimon-ai/po-web-dashboard": {
|
|
416
|
-
"version": "0.0.0-alpha.
|
|
416
|
+
"version": "0.0.0-alpha.50",
|
|
417
417
|
"dependencies": [
|
|
418
418
|
"@agimon-ai/po-core",
|
|
419
419
|
"@agimon-ai/po-web-components",
|
|
@@ -421,18 +421,18 @@
|
|
|
421
421
|
]
|
|
422
422
|
},
|
|
423
423
|
"@agimon-ai/po-web-search": {
|
|
424
|
-
"version": "0.0.0-alpha.
|
|
424
|
+
"version": "0.0.0-alpha.49",
|
|
425
425
|
"dependencies": [
|
|
426
426
|
"@agimon-ai/po-core",
|
|
427
427
|
"@agimon-ai/po-web-components"
|
|
428
428
|
]
|
|
429
429
|
},
|
|
430
430
|
"@agimon-ai/po-web-security": {
|
|
431
|
-
"version": "0.0.0-alpha.
|
|
431
|
+
"version": "0.0.0-alpha.50",
|
|
432
432
|
"dependencies": []
|
|
433
433
|
},
|
|
434
434
|
"@agimon-ai/po-workflow": {
|
|
435
|
-
"version": "0.0.0-alpha.
|
|
435
|
+
"version": "0.0.0-alpha.50",
|
|
436
436
|
"dependencies": [
|
|
437
437
|
"@agimon-ai/po-core",
|
|
438
438
|
"@agimon-ai/po-ui",
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
let _agimon_ai_po_core_platform = require("@agimon-ai/po-core/platform");
|
|
2
2
|
let node_crypto = require("node:crypto");
|
|
3
|
+
let _agimon_ai_po_core_backgroundWork = require("@agimon-ai/po-core/backgroundWork");
|
|
3
4
|
let _agimon_ai_po_core_notification = require("@agimon-ai/po-core/notification");
|
|
4
5
|
let _agimon_ai_po_notification = require("@agimon-ai/po-notification");
|
|
6
|
+
let _agimon_ai_po_autostop = require("@agimon-ai/po-autostop");
|
|
5
7
|
//#region src/builders/server/nativePush.ts
|
|
6
8
|
const MAX_CREDENTIAL_BYTES = 65536;
|
|
7
9
|
const FANOUT = 4;
|
|
@@ -94,14 +96,38 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
94
96
|
pump();
|
|
95
97
|
};
|
|
96
98
|
const tracked = /* @__PURE__ */ new Map();
|
|
99
|
+
const cancel = (held) => {
|
|
100
|
+
if (held.timer !== void 0) clearTimeout(held.timer);
|
|
101
|
+
held.timer = void 0;
|
|
102
|
+
held.holdingSince = void 0;
|
|
103
|
+
};
|
|
104
|
+
const later = (sessionId, held, run, delayMs) => {
|
|
105
|
+
if (held.timer !== void 0) clearTimeout(held.timer);
|
|
106
|
+
held.timer = setTimeout(() => {
|
|
107
|
+
held.timer = void 0;
|
|
108
|
+
finished(sessionId, held, run);
|
|
109
|
+
}, delayMs);
|
|
110
|
+
held.timer.unref?.();
|
|
111
|
+
};
|
|
112
|
+
/** Same completion test autostop applies before it closes a session: cooldown, holding work, then idle. */
|
|
97
113
|
const finished = async (sessionId, held, run) => {
|
|
98
114
|
if (held.session.parentSessionId !== void 0 || remote.state().status !== "on") return;
|
|
99
115
|
const current = () => !closed && tracked.get(sessionId) === held && held.run === run && held.session.phase === "idle";
|
|
116
|
+
if (!current()) return;
|
|
100
117
|
try {
|
|
101
118
|
const state = await hub.sessionService.readExecutionState?.(sessionId);
|
|
102
119
|
if (!current() || remote.state().status !== "on") return;
|
|
103
|
-
if (!state) throw new Error("Execution state unavailable");
|
|
104
|
-
|
|
120
|
+
if (!state?.backgroundWork) throw new Error("Execution state unavailable");
|
|
121
|
+
const holds = held.holdingSince !== void 0 && Date.now() - held.holdingSince >= _agimon_ai_po_core_backgroundWork.BACKGROUND_RUNNER_DEADLINE_MS ? _agimon_ai_po_core_backgroundWork.holdsSettledSessionAfterRunnerDeadline : _agimon_ai_po_core_backgroundWork.holdsSettledSession;
|
|
122
|
+
const { items, errors } = state.backgroundWork;
|
|
123
|
+
if (items.some(holds) || errors.some((error) => _agimon_ai_po_core_backgroundWork.BACKGROUND_WORK_HOLDING_PROVIDERS.includes(error.provider))) {
|
|
124
|
+
held.holdingSince ??= Date.now();
|
|
125
|
+
later(sessionId, held, run, _agimon_ai_po_autostop.DEFAULT_AUTO_STOP_DELAYS.cooldownMs);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const decision = (0, _agimon_ai_po_autostop.decideOnRecheck)(state, _agimon_ai_po_autostop.DEFAULT_AUTO_STOP_DELAYS);
|
|
129
|
+
if (decision.action === _agimon_ai_po_autostop.AUTO_STOP_ACTION.recheck) later(sessionId, held, run, decision.delayMs);
|
|
130
|
+
else if (decision.action === _agimon_ai_po_autostop.AUTO_STOP_ACTION.shutdown) enqueue((0, _agimon_ai_po_core_notification.createPoNotificationEntryData)((0, _agimon_ai_po_notification.settledNotification)({
|
|
105
131
|
cwd: held.session.cwd,
|
|
106
132
|
sessionName: held.session.name
|
|
107
133
|
})), sessionId);
|
|
@@ -126,12 +152,13 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
126
152
|
}
|
|
127
153
|
held.session = session;
|
|
128
154
|
if (session.phase === "turn" && !held.running) {
|
|
155
|
+
cancel(held);
|
|
129
156
|
held.running = true;
|
|
130
157
|
held.run++;
|
|
131
158
|
held.dialogs.clear();
|
|
132
159
|
} else if (session.phase === "idle" && held.running) {
|
|
133
160
|
held.running = false;
|
|
134
|
-
|
|
161
|
+
later(session.id, held, held.run, _agimon_ai_po_autostop.DEFAULT_AUTO_STOP_DELAYS.cooldownMs);
|
|
135
162
|
}
|
|
136
163
|
};
|
|
137
164
|
for (const session of hub.snapshot()) track(session);
|
|
@@ -142,6 +169,8 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
142
169
|
return;
|
|
143
170
|
}
|
|
144
171
|
if (event.kind === "removed") {
|
|
172
|
+
const held = tracked.get(event.sessionId);
|
|
173
|
+
if (held) cancel(held);
|
|
145
174
|
tracked.delete(event.sessionId);
|
|
146
175
|
return;
|
|
147
176
|
}
|
|
@@ -164,6 +193,7 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
164
193
|
return () => {
|
|
165
194
|
closed = true;
|
|
166
195
|
pending.length = 0;
|
|
196
|
+
for (const held of tracked.values()) cancel(held);
|
|
167
197
|
tracked.clear();
|
|
168
198
|
unsubscribe();
|
|
169
199
|
sender.close();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativePush.cjs","names":["readBoundedFile","BACKGROUND_CONTEXT","createPrivateKey","createPoNotificationEntryData","settledNotification","attentionNotification","notificationBody"],"sources":["../../../../src/builders/server/nativePush.ts"],"sourcesContent":["import { createPrivateKey } from 'node:crypto';\n\nimport type { HeadlessHub } from '@agimon-ai/po-core/headlessHub';\nimport { createPoNotificationEntryData } from '@agimon-ai/po-core/notification';\nimport { BACKGROUND_CONTEXT, readBoundedFile, type FileSystem } from '@agimon-ai/po-core/platform';\nimport type { RemoteRuntime } from '@agimon-ai/po-core/remoteRuntime';\nimport {\n attentionNotification,\n createNativePushSender,\n notificationBody,\n settledNotification,\n} from '@agimon-ai/po-notification';\n\ntype Sender = ReturnType<typeof createNativePushSender>;\ntype Credentials = Parameters<typeof createNativePushSender>[0];\ntype Remote = RemoteRuntime['remote'];\ntype Registration = Parameters<Sender['send']>[0];\nconst MAX_CREDENTIAL_BYTES = 64 * 1024;\nconst FANOUT = 4;\nconst MAX_PENDING = 64;\nconst SEND_TIMEOUT_MS = 10_000;\n\n/** Startup-only host credential loading. Diagnostics deliberately exclude paths and caught errors. */\nexport async function loadNativePushCredentials(\n environment: NodeJS.ProcessEnv,\n fs: FileSystem,\n notice: (message: string) => void,\n): Promise<Credentials> {\n const credentials: Credentials = { timeoutMs: SEND_TIMEOUT_MS };\n const read = async (file: string) =>\n new TextDecoder().decode(await readBoundedFile(fs, file, MAX_CREDENTIAL_BYTES, BACKGROUND_CONTEXT));\n try {\n const { PO_APNS_KEY_FILE: file, PO_APNS_KEY_ID: keyId, PO_APNS_TEAM_ID: teamId } = environment;\n if (!file || !keyId || !teamId || !/^[A-Z0-9]{10}$/u.test(keyId) || !/^[A-Z0-9]{10}$/u.test(teamId))\n throw new Error('Unavailable credentials');\n const key = await read(file);\n const parsed = createPrivateKey(key);\n if (parsed.asymmetricKeyType !== 'ec' || parsed.asymmetricKeyDetails?.namedCurve !== 'prime256v1')\n throw new Error('Invalid key');\n credentials.apns = { key, keyId, teamId };\n } catch {\n notice('Native push APNs disabled: missing or invalid credentials.');\n }\n try {\n const file = environment.PO_FCM_SERVICE_ACCOUNT_FILE;\n if (!file) throw new Error('Unavailable credentials');\n const value: unknown = JSON.parse(await read(file));\n if (!value || typeof value !== 'object') throw new Error('Invalid account');\n const account = value as Record<string, unknown>;\n const { client_email: clientEmail, private_key: privateKey, project_id: projectId } = account;\n if (\n account.type !== 'service_account' ||\n typeof clientEmail !== 'string' ||\n !/^[^\\s@]+@[^\\s@]+$/u.test(clientEmail) ||\n typeof projectId !== 'string' ||\n !/^[a-z][a-z0-9-]{4,61}[a-z0-9]$/u.test(projectId) ||\n typeof privateKey !== 'string'\n )\n throw new Error('Invalid account');\n const parsed = createPrivateKey(privateKey);\n if (parsed.asymmetricKeyType !== 'rsa' || (parsed.asymmetricKeyDetails?.modulusLength ?? 0) < 2048)\n throw new Error('Invalid key');\n credentials.fcm = { clientEmail, privateKey, projectId };\n } catch {\n notice('Native push FCM disabled: missing or invalid credentials.');\n }\n return credentials;\n}\n\nfunction endpoint(registration: Registration): string {\n return JSON.stringify([\n registration.platform,\n registration.token,\n registration.hostRef ?? null,\n registration.platform === 'ios' ? registration.environment : null,\n ]);\n}\n\n/** One live subscription for the entire hub, with no transcript reads or socket dependency. */\nexport function subscribeNativePush(\n hub: Pick<HeadlessHub, 'onEvent' | 'snapshot' | 'sessionService'>,\n remote: Pick<Remote, 'state' | 'listNativePushRegistrations' | 'clearNativePushRegistration'>,\n sender: Sender,\n notice: (message: string) => void,\n): () => void {\n type Job = {\n owners: ReturnType<Remote['listNativePushRegistrations']>;\n notification: Parameters<Sender['send']>[1];\n sessionId: string;\n };\n const pending: Job[] = [];\n let active = 0;\n let closed = false;\n const pump = (): void => {\n while (!closed && active < FANOUT && pending.length > 0) {\n const job = pending.shift()!;\n if (remote.state().status !== 'on') continue;\n const current = remote.listNativePushRegistrations();\n const owners = job.owners.filter((owner) =>\n current.some(\n (held) =>\n held.notificationId === owner.notificationId &&\n endpoint(held.registration) === endpoint(owner.registration),\n ),\n );\n if (owners.length === 0) continue;\n active++;\n void sender\n .send(owners[0]!.registration, job.notification, job.sessionId)\n .then((result) => {\n if (!closed && result.invalid)\n for (const owner of owners) remote.clearNativePushRegistration(owner.notificationId, owner.registration);\n })\n .catch(() => notice('Native push delivery failed.'))\n .finally(() => {\n active--;\n pump();\n });\n }\n };\n const enqueue = (notification: Job['notification'] | undefined, sessionId: string): void => {\n if (!notification || closed || remote.state().status !== 'on') return;\n const groups = new Map<string, Job['owners']>();\n for (const owner of remote.listNativePushRegistrations()) {\n const key = endpoint(owner.registration);\n const group = groups.get(key);\n if (group) group.push(owner);\n else groups.set(key, [owner]);\n }\n for (const owners of groups.values()) {\n if (pending.length + active >= MAX_PENDING) break; // Best effort, never an outbox.\n pending.push({ owners, notification, sessionId });\n }\n pump();\n };\n type Session = ReturnType<HeadlessHub['snapshot']>[number];\n type Tracked = {\n session: Session;\n running: boolean;\n run: number;\n dialogs: Set<string>;\n warned: boolean;\n };\n const tracked = new Map<string, Tracked>();\n const finished = async (sessionId: string, held: Tracked, run: number): Promise<void> => {\n if (held.session.parentSessionId !== undefined || remote.state().status !== 'on') return;\n const current = () =>\n !closed && tracked.get(sessionId) === held && held.run === run && held.session.phase === 'idle';\n try {\n // Hub summaries do not maintain pendingMessageCount. Only the host knows its queue.\n const state = await hub.sessionService.readExecutionState?.(sessionId);\n if (!current() || remote.state().status !== 'on') return;\n if (!state) throw new Error('Execution state unavailable');\n if (state.isIdle && !state.hasPendingMessages)\n enqueue(\n createPoNotificationEntryData(settledNotification({ cwd: held.session.cwd, sessionName: held.session.name })),\n sessionId,\n );\n } catch {\n // ponytail: mirrors without a state reader stay quiet; add a mirror reader for completion parity.\n if (current() && remote.state().status === 'on' && !held.warned) {\n held.warned = true;\n notice('Native push completion check unavailable.');\n }\n }\n };\n const track = (session: Session): void => {\n let held = tracked.get(session.id);\n if (!held) {\n held = { session, running: false, run: 0, dialogs: new Set(), warned: false };\n tracked.set(session.id, held);\n }\n held.session = session;\n if (session.phase === 'turn' && !held.running) {\n held.running = true;\n held.run++;\n held.dialogs.clear();\n } else if (session.phase === 'idle' && held.running) {\n held.running = false;\n void finished(session.id, held, held.run);\n }\n };\n for (const session of hub.snapshot()) track(session);\n const unsubscribe = hub.onEvent((event) => {\n if (closed) return;\n if (event.kind === 'upsert') {\n track(event.session);\n return;\n }\n if (event.kind === 'removed') {\n tracked.delete(event.sessionId);\n return;\n }\n // Toasts stay in-app: subagent and background completions would otherwise buzz the phone for every run.\n if (event.kind !== 'frame' || event.frame.type !== 'extension_ui_request') return;\n const { frame, sessionId } = event;\n const held = tracked.get(sessionId);\n if (\n !held ||\n held.session.parentSessionId !== undefined ||\n held.session.phase !== 'turn' ||\n typeof frame.method !== 'string' ||\n !['select', 'confirm', 'input', 'editor'].includes(frame.method) ||\n typeof frame.id !== 'string' ||\n !frame.id.trim() ||\n held.dialogs.has(frame.id)\n )\n return;\n held.dialogs.add(frame.id);\n const text = [frame.message, frame.title].find(\n (value): value is string => typeof value === 'string' && !!value.trim(),\n );\n enqueue(\n createPoNotificationEntryData({\n ...attentionNotification(notificationBody(text ?? 'A question is waiting for your answer.')),\n subtitle: held.session.name,\n }),\n sessionId,\n );\n });\n return () => {\n closed = true;\n pending.length = 0;\n tracked.clear();\n unsubscribe();\n sender.close();\n };\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"nativePush.cjs","names":["readBoundedFile","BACKGROUND_CONTEXT","createPrivateKey","BACKGROUND_RUNNER_DEADLINE_MS","holdsSettledSessionAfterRunnerDeadline","holdsSettledSession","BACKGROUND_WORK_HOLDING_PROVIDERS","DEFAULT_AUTO_STOP_DELAYS","decideOnRecheck","AUTO_STOP_ACTION","createPoNotificationEntryData","settledNotification","attentionNotification","notificationBody"],"sources":["../../../../src/builders/server/nativePush.ts"],"sourcesContent":["import { createPrivateKey } from 'node:crypto';\n\nimport { AUTO_STOP_ACTION, DEFAULT_AUTO_STOP_DELAYS, decideOnRecheck } from '@agimon-ai/po-autostop';\nimport {\n BACKGROUND_RUNNER_DEADLINE_MS,\n BACKGROUND_WORK_HOLDING_PROVIDERS,\n holdsSettledSession,\n holdsSettledSessionAfterRunnerDeadline,\n} from '@agimon-ai/po-core/backgroundWork';\nimport type { HeadlessHub } from '@agimon-ai/po-core/headlessHub';\nimport { createPoNotificationEntryData } from '@agimon-ai/po-core/notification';\nimport { BACKGROUND_CONTEXT, readBoundedFile, type FileSystem } from '@agimon-ai/po-core/platform';\nimport type { RemoteRuntime } from '@agimon-ai/po-core/remoteRuntime';\nimport {\n attentionNotification,\n createNativePushSender,\n notificationBody,\n settledNotification,\n} from '@agimon-ai/po-notification';\n\ntype Sender = ReturnType<typeof createNativePushSender>;\ntype Credentials = Parameters<typeof createNativePushSender>[0];\ntype Remote = RemoteRuntime['remote'];\ntype Registration = Parameters<Sender['send']>[0];\nconst MAX_CREDENTIAL_BYTES = 64 * 1024;\nconst FANOUT = 4;\nconst MAX_PENDING = 64;\nconst SEND_TIMEOUT_MS = 10_000;\n\n/** Startup-only host credential loading. Diagnostics deliberately exclude paths and caught errors. */\nexport async function loadNativePushCredentials(\n environment: NodeJS.ProcessEnv,\n fs: FileSystem,\n notice: (message: string) => void,\n): Promise<Credentials> {\n const credentials: Credentials = { timeoutMs: SEND_TIMEOUT_MS };\n const read = async (file: string) =>\n new TextDecoder().decode(await readBoundedFile(fs, file, MAX_CREDENTIAL_BYTES, BACKGROUND_CONTEXT));\n try {\n const { PO_APNS_KEY_FILE: file, PO_APNS_KEY_ID: keyId, PO_APNS_TEAM_ID: teamId } = environment;\n if (!file || !keyId || !teamId || !/^[A-Z0-9]{10}$/u.test(keyId) || !/^[A-Z0-9]{10}$/u.test(teamId))\n throw new Error('Unavailable credentials');\n const key = await read(file);\n const parsed = createPrivateKey(key);\n if (parsed.asymmetricKeyType !== 'ec' || parsed.asymmetricKeyDetails?.namedCurve !== 'prime256v1')\n throw new Error('Invalid key');\n credentials.apns = { key, keyId, teamId };\n } catch {\n notice('Native push APNs disabled: missing or invalid credentials.');\n }\n try {\n const file = environment.PO_FCM_SERVICE_ACCOUNT_FILE;\n if (!file) throw new Error('Unavailable credentials');\n const value: unknown = JSON.parse(await read(file));\n if (!value || typeof value !== 'object') throw new Error('Invalid account');\n const account = value as Record<string, unknown>;\n const { client_email: clientEmail, private_key: privateKey, project_id: projectId } = account;\n if (\n account.type !== 'service_account' ||\n typeof clientEmail !== 'string' ||\n !/^[^\\s@]+@[^\\s@]+$/u.test(clientEmail) ||\n typeof projectId !== 'string' ||\n !/^[a-z][a-z0-9-]{4,61}[a-z0-9]$/u.test(projectId) ||\n typeof privateKey !== 'string'\n )\n throw new Error('Invalid account');\n const parsed = createPrivateKey(privateKey);\n if (parsed.asymmetricKeyType !== 'rsa' || (parsed.asymmetricKeyDetails?.modulusLength ?? 0) < 2048)\n throw new Error('Invalid key');\n credentials.fcm = { clientEmail, privateKey, projectId };\n } catch {\n notice('Native push FCM disabled: missing or invalid credentials.');\n }\n return credentials;\n}\n\nfunction endpoint(registration: Registration): string {\n return JSON.stringify([\n registration.platform,\n registration.token,\n registration.hostRef ?? null,\n registration.platform === 'ios' ? registration.environment : null,\n ]);\n}\n\n/** One live subscription for the entire hub, with no transcript reads or socket dependency. */\nexport function subscribeNativePush(\n hub: Pick<HeadlessHub, 'onEvent' | 'snapshot' | 'sessionService'>,\n remote: Pick<Remote, 'state' | 'listNativePushRegistrations' | 'clearNativePushRegistration'>,\n sender: Sender,\n notice: (message: string) => void,\n): () => void {\n type Job = {\n owners: ReturnType<Remote['listNativePushRegistrations']>;\n notification: Parameters<Sender['send']>[1];\n sessionId: string;\n };\n const pending: Job[] = [];\n let active = 0;\n let closed = false;\n const pump = (): void => {\n while (!closed && active < FANOUT && pending.length > 0) {\n const job = pending.shift()!;\n if (remote.state().status !== 'on') continue;\n const current = remote.listNativePushRegistrations();\n const owners = job.owners.filter((owner) =>\n current.some(\n (held) =>\n held.notificationId === owner.notificationId &&\n endpoint(held.registration) === endpoint(owner.registration),\n ),\n );\n if (owners.length === 0) continue;\n active++;\n void sender\n .send(owners[0]!.registration, job.notification, job.sessionId)\n .then((result) => {\n if (!closed && result.invalid)\n for (const owner of owners) remote.clearNativePushRegistration(owner.notificationId, owner.registration);\n })\n .catch(() => notice('Native push delivery failed.'))\n .finally(() => {\n active--;\n pump();\n });\n }\n };\n const enqueue = (notification: Job['notification'] | undefined, sessionId: string): void => {\n if (!notification || closed || remote.state().status !== 'on') return;\n const groups = new Map<string, Job['owners']>();\n for (const owner of remote.listNativePushRegistrations()) {\n const key = endpoint(owner.registration);\n const group = groups.get(key);\n if (group) group.push(owner);\n else groups.set(key, [owner]);\n }\n for (const owners of groups.values()) {\n if (pending.length + active >= MAX_PENDING) break; // Best effort, never an outbox.\n pending.push({ owners, notification, sessionId });\n }\n pump();\n };\n type Session = ReturnType<HeadlessHub['snapshot']>[number];\n type Tracked = {\n session: Session;\n running: boolean;\n run: number;\n dialogs: Set<string>;\n warned: boolean;\n timer?: ReturnType<typeof setTimeout>;\n holdingSince?: number;\n };\n const tracked = new Map<string, Tracked>();\n const cancel = (held: Tracked): void => {\n if (held.timer !== undefined) clearTimeout(held.timer);\n held.timer = undefined;\n held.holdingSince = undefined;\n };\n const later = (sessionId: string, held: Tracked, run: number, delayMs: number): void => {\n if (held.timer !== undefined) clearTimeout(held.timer);\n held.timer = setTimeout(() => {\n held.timer = undefined;\n void finished(sessionId, held, run);\n }, delayMs);\n held.timer.unref?.();\n };\n /** Same completion test autostop applies before it closes a session: cooldown, holding work, then idle. */\n const finished = async (sessionId: string, held: Tracked, run: number): Promise<void> => {\n if (held.session.parentSessionId !== undefined || remote.state().status !== 'on') return;\n const current = () =>\n !closed && tracked.get(sessionId) === held && held.run === run && held.session.phase === 'idle';\n if (!current()) return;\n try {\n // Hub summaries do not maintain pendingMessageCount. Only the host knows its queue.\n const state = await hub.sessionService.readExecutionState?.(sessionId);\n if (!current() || remote.state().status !== 'on') return;\n // Unknown background work cannot prove the run finished.\n if (!state?.backgroundWork) throw new Error('Execution state unavailable');\n const expired =\n held.holdingSince !== undefined && Date.now() - held.holdingSince >= BACKGROUND_RUNNER_DEADLINE_MS;\n const holds = expired ? holdsSettledSessionAfterRunnerDeadline : holdsSettledSession;\n const { items, errors } = state.backgroundWork;\n if (items.some(holds) || errors.some((error) => BACKGROUND_WORK_HOLDING_PROVIDERS.includes(error.provider))) {\n held.holdingSince ??= Date.now();\n later(sessionId, held, run, DEFAULT_AUTO_STOP_DELAYS.cooldownMs);\n return;\n }\n const decision = decideOnRecheck(state, DEFAULT_AUTO_STOP_DELAYS);\n if (decision.action === AUTO_STOP_ACTION.recheck) later(sessionId, held, run, decision.delayMs);\n else if (decision.action === AUTO_STOP_ACTION.shutdown)\n enqueue(\n createPoNotificationEntryData(settledNotification({ cwd: held.session.cwd, sessionName: held.session.name })),\n sessionId,\n );\n } catch {\n // ponytail: mirrors without a state reader stay quiet; add a mirror reader for completion parity.\n if (current() && remote.state().status === 'on' && !held.warned) {\n held.warned = true;\n notice('Native push completion check unavailable.');\n }\n }\n };\n const track = (session: Session): void => {\n let held = tracked.get(session.id);\n if (!held) {\n held = { session, running: false, run: 0, dialogs: new Set(), warned: false };\n tracked.set(session.id, held);\n }\n held.session = session;\n if (session.phase === 'turn' && !held.running) {\n cancel(held);\n held.running = true;\n held.run++;\n held.dialogs.clear();\n } else if (session.phase === 'idle' && held.running) {\n held.running = false;\n later(session.id, held, held.run, DEFAULT_AUTO_STOP_DELAYS.cooldownMs);\n }\n };\n for (const session of hub.snapshot()) track(session);\n const unsubscribe = hub.onEvent((event) => {\n if (closed) return;\n if (event.kind === 'upsert') {\n track(event.session);\n return;\n }\n if (event.kind === 'removed') {\n const held = tracked.get(event.sessionId);\n if (held) cancel(held);\n tracked.delete(event.sessionId);\n return;\n }\n // Toasts stay in-app: subagent and background completions would otherwise buzz the phone for every run.\n if (event.kind !== 'frame' || event.frame.type !== 'extension_ui_request') return;\n const { frame, sessionId } = event;\n const held = tracked.get(sessionId);\n if (\n !held ||\n held.session.parentSessionId !== undefined ||\n held.session.phase !== 'turn' ||\n typeof frame.method !== 'string' ||\n !['select', 'confirm', 'input', 'editor'].includes(frame.method) ||\n typeof frame.id !== 'string' ||\n !frame.id.trim() ||\n held.dialogs.has(frame.id)\n )\n return;\n held.dialogs.add(frame.id);\n const text = [frame.message, frame.title].find(\n (value): value is string => typeof value === 'string' && !!value.trim(),\n );\n enqueue(\n createPoNotificationEntryData({\n ...attentionNotification(notificationBody(text ?? 'A question is waiting for your answer.')),\n subtitle: held.session.name,\n }),\n sessionId,\n );\n });\n return () => {\n closed = true;\n pending.length = 0;\n for (const held of tracked.values()) cancel(held);\n tracked.clear();\n unsubscribe();\n sender.close();\n };\n}\n"],"mappings":"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"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { BACKGROUND_CONTEXT, readBoundedFile } from "@agimon-ai/po-core/platform";
|
|
2
2
|
import { createPrivateKey } from "node:crypto";
|
|
3
|
+
import { BACKGROUND_RUNNER_DEADLINE_MS, BACKGROUND_WORK_HOLDING_PROVIDERS, holdsSettledSession, holdsSettledSessionAfterRunnerDeadline } from "@agimon-ai/po-core/backgroundWork";
|
|
3
4
|
import { createPoNotificationEntryData } from "@agimon-ai/po-core/notification";
|
|
4
5
|
import { attentionNotification, notificationBody, settledNotification } from "@agimon-ai/po-notification";
|
|
6
|
+
import { AUTO_STOP_ACTION, DEFAULT_AUTO_STOP_DELAYS, decideOnRecheck } from "@agimon-ai/po-autostop";
|
|
5
7
|
//#region src/builders/server/nativePush.ts
|
|
6
8
|
const MAX_CREDENTIAL_BYTES = 65536;
|
|
7
9
|
const FANOUT = 4;
|
|
@@ -94,14 +96,38 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
94
96
|
pump();
|
|
95
97
|
};
|
|
96
98
|
const tracked = /* @__PURE__ */ new Map();
|
|
99
|
+
const cancel = (held) => {
|
|
100
|
+
if (held.timer !== void 0) clearTimeout(held.timer);
|
|
101
|
+
held.timer = void 0;
|
|
102
|
+
held.holdingSince = void 0;
|
|
103
|
+
};
|
|
104
|
+
const later = (sessionId, held, run, delayMs) => {
|
|
105
|
+
if (held.timer !== void 0) clearTimeout(held.timer);
|
|
106
|
+
held.timer = setTimeout(() => {
|
|
107
|
+
held.timer = void 0;
|
|
108
|
+
finished(sessionId, held, run);
|
|
109
|
+
}, delayMs);
|
|
110
|
+
held.timer.unref?.();
|
|
111
|
+
};
|
|
112
|
+
/** Same completion test autostop applies before it closes a session: cooldown, holding work, then idle. */
|
|
97
113
|
const finished = async (sessionId, held, run) => {
|
|
98
114
|
if (held.session.parentSessionId !== void 0 || remote.state().status !== "on") return;
|
|
99
115
|
const current = () => !closed && tracked.get(sessionId) === held && held.run === run && held.session.phase === "idle";
|
|
116
|
+
if (!current()) return;
|
|
100
117
|
try {
|
|
101
118
|
const state = await hub.sessionService.readExecutionState?.(sessionId);
|
|
102
119
|
if (!current() || remote.state().status !== "on") return;
|
|
103
|
-
if (!state) throw new Error("Execution state unavailable");
|
|
104
|
-
|
|
120
|
+
if (!state?.backgroundWork) throw new Error("Execution state unavailable");
|
|
121
|
+
const holds = held.holdingSince !== void 0 && Date.now() - held.holdingSince >= BACKGROUND_RUNNER_DEADLINE_MS ? holdsSettledSessionAfterRunnerDeadline : holdsSettledSession;
|
|
122
|
+
const { items, errors } = state.backgroundWork;
|
|
123
|
+
if (items.some(holds) || errors.some((error) => BACKGROUND_WORK_HOLDING_PROVIDERS.includes(error.provider))) {
|
|
124
|
+
held.holdingSince ??= Date.now();
|
|
125
|
+
later(sessionId, held, run, DEFAULT_AUTO_STOP_DELAYS.cooldownMs);
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const decision = decideOnRecheck(state, DEFAULT_AUTO_STOP_DELAYS);
|
|
129
|
+
if (decision.action === AUTO_STOP_ACTION.recheck) later(sessionId, held, run, decision.delayMs);
|
|
130
|
+
else if (decision.action === AUTO_STOP_ACTION.shutdown) enqueue(createPoNotificationEntryData(settledNotification({
|
|
105
131
|
cwd: held.session.cwd,
|
|
106
132
|
sessionName: held.session.name
|
|
107
133
|
})), sessionId);
|
|
@@ -126,12 +152,13 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
126
152
|
}
|
|
127
153
|
held.session = session;
|
|
128
154
|
if (session.phase === "turn" && !held.running) {
|
|
155
|
+
cancel(held);
|
|
129
156
|
held.running = true;
|
|
130
157
|
held.run++;
|
|
131
158
|
held.dialogs.clear();
|
|
132
159
|
} else if (session.phase === "idle" && held.running) {
|
|
133
160
|
held.running = false;
|
|
134
|
-
|
|
161
|
+
later(session.id, held, held.run, DEFAULT_AUTO_STOP_DELAYS.cooldownMs);
|
|
135
162
|
}
|
|
136
163
|
};
|
|
137
164
|
for (const session of hub.snapshot()) track(session);
|
|
@@ -142,6 +169,8 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
142
169
|
return;
|
|
143
170
|
}
|
|
144
171
|
if (event.kind === "removed") {
|
|
172
|
+
const held = tracked.get(event.sessionId);
|
|
173
|
+
if (held) cancel(held);
|
|
145
174
|
tracked.delete(event.sessionId);
|
|
146
175
|
return;
|
|
147
176
|
}
|
|
@@ -164,6 +193,7 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
164
193
|
return () => {
|
|
165
194
|
closed = true;
|
|
166
195
|
pending.length = 0;
|
|
196
|
+
for (const held of tracked.values()) cancel(held);
|
|
167
197
|
tracked.clear();
|
|
168
198
|
unsubscribe();
|
|
169
199
|
sender.close();
|