@agimon-ai/po 0.0.0-alpha.113 → 0.0.0-alpha.115
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 +61 -59
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/dist/src/builders/server/nativePush.cjs +8 -12
- package/dist/src/builders/server/nativePush.cjs.map +1 -1
- package/dist/src/builders/server/nativePush.mjs +9 -13
- package/dist/src/builders/server/nativePush.mjs.map +1 -1
- package/package.json +27 -27
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.115",
|
|
6
6
|
"dependencies": [
|
|
7
7
|
"@agimon-ai/po-approval",
|
|
8
8
|
"@agimon-ai/po-artifact",
|
|
@@ -28,14 +28,14 @@
|
|
|
28
28
|
]
|
|
29
29
|
},
|
|
30
30
|
"@agimon-ai/po-approval": {
|
|
31
|
-
"version": "0.0.0-alpha.
|
|
31
|
+
"version": "0.0.0-alpha.114",
|
|
32
32
|
"dependencies": [
|
|
33
33
|
"@agimon-ai/po-core",
|
|
34
34
|
"@agimon-ai/po-web-components"
|
|
35
35
|
]
|
|
36
36
|
},
|
|
37
37
|
"@agimon-ai/po-artifact": {
|
|
38
|
-
"version": "0.0.0-alpha.
|
|
38
|
+
"version": "0.0.0-alpha.113",
|
|
39
39
|
"dependencies": [
|
|
40
40
|
"@agimon-ai/po-core",
|
|
41
41
|
"@agimon-ai/po-web-components",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
]
|
|
44
44
|
},
|
|
45
45
|
"@agimon-ai/po-author": {
|
|
46
|
-
"version": "0.0.0-alpha.
|
|
46
|
+
"version": "0.0.0-alpha.114",
|
|
47
47
|
"dependencies": [
|
|
48
48
|
"@agimon-ai/po-artifact",
|
|
49
49
|
"@agimon-ai/po-core",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
]
|
|
54
54
|
},
|
|
55
55
|
"@agimon-ai/po-autocompact": {
|
|
56
|
-
"version": "0.0.0-alpha.
|
|
56
|
+
"version": "0.0.0-alpha.114",
|
|
57
57
|
"dependencies": [
|
|
58
58
|
"@agimon-ai/po-artifact",
|
|
59
59
|
"@agimon-ai/po-config",
|
|
@@ -62,24 +62,24 @@
|
|
|
62
62
|
]
|
|
63
63
|
},
|
|
64
64
|
"@agimon-ai/po-autostop": {
|
|
65
|
-
"version": "0.0.0-alpha.
|
|
65
|
+
"version": "0.0.0-alpha.114",
|
|
66
66
|
"dependencies": [
|
|
67
67
|
"@agimon-ai/po-core"
|
|
68
68
|
]
|
|
69
69
|
},
|
|
70
70
|
"@agimon-ai/po-browse": {
|
|
71
|
-
"version": "0.0.1-alpha.
|
|
71
|
+
"version": "0.0.1-alpha.112",
|
|
72
72
|
"dependencies": [
|
|
73
73
|
"@agimon-ai/po-core",
|
|
74
74
|
"@agimon-ai/po-web-components"
|
|
75
75
|
]
|
|
76
76
|
},
|
|
77
77
|
"@agimon-ai/po-build": {
|
|
78
|
-
"version": "0.0.0-alpha.
|
|
78
|
+
"version": "0.0.0-alpha.114",
|
|
79
79
|
"dependencies": []
|
|
80
80
|
},
|
|
81
81
|
"@agimon-ai/po-cache": {
|
|
82
|
-
"version": "0.0.0-alpha.
|
|
82
|
+
"version": "0.0.0-alpha.114",
|
|
83
83
|
"dependencies": [
|
|
84
84
|
"@agimon-ai/po-config",
|
|
85
85
|
"@agimon-ai/po-core",
|
|
@@ -87,7 +87,7 @@
|
|
|
87
87
|
]
|
|
88
88
|
},
|
|
89
89
|
"@agimon-ai/po-calendar": {
|
|
90
|
-
"version": "0.0.1-alpha.
|
|
90
|
+
"version": "0.0.1-alpha.73",
|
|
91
91
|
"dependencies": [
|
|
92
92
|
"@agimon-ai/po-config",
|
|
93
93
|
"@agimon-ai/po-core",
|
|
@@ -99,11 +99,11 @@
|
|
|
99
99
|
]
|
|
100
100
|
},
|
|
101
101
|
"@agimon-ai/po-claude-bridge": {
|
|
102
|
-
"version": "0.1.1-alpha.
|
|
102
|
+
"version": "0.1.1-alpha.94",
|
|
103
103
|
"dependencies": []
|
|
104
104
|
},
|
|
105
105
|
"@agimon-ai/po-codemode": {
|
|
106
|
-
"version": "0.0.1-alpha.
|
|
106
|
+
"version": "0.0.1-alpha.87",
|
|
107
107
|
"dependencies": [
|
|
108
108
|
"@agimon-ai/po-config",
|
|
109
109
|
"@agimon-ai/po-core",
|
|
@@ -111,7 +111,7 @@
|
|
|
111
111
|
]
|
|
112
112
|
},
|
|
113
113
|
"@agimon-ai/po-computer-use": {
|
|
114
|
-
"version": "0.0.0-alpha.
|
|
114
|
+
"version": "0.0.0-alpha.114",
|
|
115
115
|
"dependencies": [
|
|
116
116
|
"@agimon-ai/po-config",
|
|
117
117
|
"@agimon-ai/po-core",
|
|
@@ -121,26 +121,26 @@
|
|
|
121
121
|
]
|
|
122
122
|
},
|
|
123
123
|
"@agimon-ai/po-config": {
|
|
124
|
-
"version": "0.0.0-alpha.
|
|
124
|
+
"version": "0.0.0-alpha.114",
|
|
125
125
|
"dependencies": [
|
|
126
126
|
"@agimon-ai/po-core",
|
|
127
127
|
"@agimon-ai/po-web-components"
|
|
128
128
|
]
|
|
129
129
|
},
|
|
130
130
|
"@agimon-ai/po-core": {
|
|
131
|
-
"version": "0.0.0-alpha.
|
|
131
|
+
"version": "0.0.0-alpha.114",
|
|
132
132
|
"dependencies": [
|
|
133
133
|
"@agimon-ai/po-web-security"
|
|
134
134
|
]
|
|
135
135
|
},
|
|
136
136
|
"@agimon-ai/po-db": {
|
|
137
|
-
"version": "0.0.0-alpha.
|
|
137
|
+
"version": "0.0.0-alpha.114",
|
|
138
138
|
"dependencies": [
|
|
139
139
|
"@agimon-ai/po-core"
|
|
140
140
|
]
|
|
141
141
|
},
|
|
142
142
|
"@agimon-ai/po-domain": {
|
|
143
|
-
"version": "0.0.0-alpha.
|
|
143
|
+
"version": "0.0.0-alpha.114",
|
|
144
144
|
"dependencies": [
|
|
145
145
|
"@agimon-ai/po-config",
|
|
146
146
|
"@agimon-ai/po-core",
|
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
]
|
|
151
151
|
},
|
|
152
152
|
"@agimon-ai/po-edit": {
|
|
153
|
-
"version": "0.0.0-alpha.
|
|
153
|
+
"version": "0.0.0-alpha.114",
|
|
154
154
|
"dependencies": [
|
|
155
155
|
"@agimon-ai/po-core",
|
|
156
156
|
"@agimon-ai/po-hashline",
|
|
@@ -159,7 +159,7 @@
|
|
|
159
159
|
]
|
|
160
160
|
},
|
|
161
161
|
"@agimon-ai/po-file-edit": {
|
|
162
|
-
"version": "0.0.0-alpha.
|
|
162
|
+
"version": "0.0.0-alpha.114",
|
|
163
163
|
"dependencies": [
|
|
164
164
|
"@agimon-ai/po-config",
|
|
165
165
|
"@agimon-ai/po-core",
|
|
@@ -169,7 +169,7 @@
|
|
|
169
169
|
]
|
|
170
170
|
},
|
|
171
171
|
"@agimon-ai/po-git": {
|
|
172
|
-
"version": "0.0.0-alpha.
|
|
172
|
+
"version": "0.0.0-alpha.114",
|
|
173
173
|
"dependencies": [
|
|
174
174
|
"@agimon-ai/po-core",
|
|
175
175
|
"@agimon-ai/po-session",
|
|
@@ -178,7 +178,7 @@
|
|
|
178
178
|
]
|
|
179
179
|
},
|
|
180
180
|
"@agimon-ai/po-goal": {
|
|
181
|
-
"version": "0.0.0-alpha.
|
|
181
|
+
"version": "0.0.0-alpha.114",
|
|
182
182
|
"dependencies": [
|
|
183
183
|
"@agimon-ai/po-core",
|
|
184
184
|
"@agimon-ai/po-minor-mode",
|
|
@@ -187,7 +187,7 @@
|
|
|
187
187
|
]
|
|
188
188
|
},
|
|
189
189
|
"@agimon-ai/po-grep": {
|
|
190
|
-
"version": "0.0.0-alpha.
|
|
190
|
+
"version": "0.0.0-alpha.114",
|
|
191
191
|
"dependencies": [
|
|
192
192
|
"@agimon-ai/po-core",
|
|
193
193
|
"@agimon-ai/po-hashline",
|
|
@@ -196,11 +196,11 @@
|
|
|
196
196
|
]
|
|
197
197
|
},
|
|
198
198
|
"@agimon-ai/po-hashline": {
|
|
199
|
-
"version": "0.0.0-alpha.
|
|
199
|
+
"version": "0.0.0-alpha.114",
|
|
200
200
|
"dependencies": []
|
|
201
201
|
},
|
|
202
202
|
"@agimon-ai/po-help": {
|
|
203
|
-
"version": "0.0.0-alpha.
|
|
203
|
+
"version": "0.0.0-alpha.114",
|
|
204
204
|
"dependencies": [
|
|
205
205
|
"@agimon-ai/po-core",
|
|
206
206
|
"@agimon-ai/po-minor-mode",
|
|
@@ -209,14 +209,14 @@
|
|
|
209
209
|
]
|
|
210
210
|
},
|
|
211
211
|
"@agimon-ai/po-identity": {
|
|
212
|
-
"version": "0.0.2-alpha.
|
|
212
|
+
"version": "0.0.2-alpha.61",
|
|
213
213
|
"dependencies": [
|
|
214
214
|
"@agimon-ai/po-core",
|
|
215
215
|
"@agimon-ai/po-web-security"
|
|
216
216
|
]
|
|
217
217
|
},
|
|
218
218
|
"@agimon-ai/po-image-gen": {
|
|
219
|
-
"version": "0.0.0-alpha.
|
|
219
|
+
"version": "0.0.0-alpha.113",
|
|
220
220
|
"dependencies": [
|
|
221
221
|
"@agimon-ai/po-core",
|
|
222
222
|
"@agimon-ai/po-web-components",
|
|
@@ -224,7 +224,7 @@
|
|
|
224
224
|
]
|
|
225
225
|
},
|
|
226
226
|
"@agimon-ai/po-ios": {
|
|
227
|
-
"version": "0.0.1-alpha.
|
|
227
|
+
"version": "0.0.1-alpha.49",
|
|
228
228
|
"dependencies": [
|
|
229
229
|
"@agimon-ai/po-artifact",
|
|
230
230
|
"@agimon-ai/po-config",
|
|
@@ -234,7 +234,7 @@
|
|
|
234
234
|
]
|
|
235
235
|
},
|
|
236
236
|
"@agimon-ai/po-log": {
|
|
237
|
-
"version": "0.0.0-alpha.
|
|
237
|
+
"version": "0.0.0-alpha.114",
|
|
238
238
|
"dependencies": [
|
|
239
239
|
"@agimon-ai/po-core",
|
|
240
240
|
"@agimon-ai/po-web-components",
|
|
@@ -242,7 +242,7 @@
|
|
|
242
242
|
]
|
|
243
243
|
},
|
|
244
244
|
"@agimon-ai/po-major-mode": {
|
|
245
|
-
"version": "0.0.0-alpha.
|
|
245
|
+
"version": "0.0.0-alpha.114",
|
|
246
246
|
"dependencies": [
|
|
247
247
|
"@agimon-ai/po-config",
|
|
248
248
|
"@agimon-ai/po-core",
|
|
@@ -250,7 +250,7 @@
|
|
|
250
250
|
]
|
|
251
251
|
},
|
|
252
252
|
"@agimon-ai/po-mcp": {
|
|
253
|
-
"version": "0.0.0-alpha.
|
|
253
|
+
"version": "0.0.0-alpha.114",
|
|
254
254
|
"dependencies": [
|
|
255
255
|
"@agimon-ai/po-config",
|
|
256
256
|
"@agimon-ai/po-core",
|
|
@@ -261,43 +261,44 @@
|
|
|
261
261
|
]
|
|
262
262
|
},
|
|
263
263
|
"@agimon-ai/po-mcp-proxy": {
|
|
264
|
-
"version": "0.0.1-alpha.
|
|
264
|
+
"version": "0.0.1-alpha.93",
|
|
265
265
|
"dependencies": []
|
|
266
266
|
},
|
|
267
267
|
"@agimon-ai/po-minor-mode": {
|
|
268
|
-
"version": "0.0.0-alpha.
|
|
268
|
+
"version": "0.0.0-alpha.114",
|
|
269
269
|
"dependencies": [
|
|
270
270
|
"@agimon-ai/po-core"
|
|
271
271
|
]
|
|
272
272
|
},
|
|
273
273
|
"@agimon-ai/po-model-guidance": {
|
|
274
|
-
"version": "0.0.0-alpha.
|
|
274
|
+
"version": "0.0.0-alpha.114",
|
|
275
275
|
"dependencies": [
|
|
276
276
|
"@agimon-ai/po-config",
|
|
277
277
|
"@agimon-ai/po-core"
|
|
278
278
|
]
|
|
279
279
|
},
|
|
280
280
|
"@agimon-ai/po-native-components": {
|
|
281
|
-
"version": "0.0.0-alpha.
|
|
281
|
+
"version": "0.0.0-alpha.114",
|
|
282
282
|
"dependencies": [
|
|
283
283
|
"@agimon-ai/po-web-components"
|
|
284
284
|
]
|
|
285
285
|
},
|
|
286
286
|
"@agimon-ai/po-network": {
|
|
287
|
-
"version": "0.0.2-alpha.
|
|
287
|
+
"version": "0.0.2-alpha.61",
|
|
288
288
|
"dependencies": [
|
|
289
289
|
"@agimon-ai/po-core",
|
|
290
290
|
"@agimon-ai/po-web-security"
|
|
291
291
|
]
|
|
292
292
|
},
|
|
293
293
|
"@agimon-ai/po-notification": {
|
|
294
|
-
"version": "0.0.0-alpha.
|
|
294
|
+
"version": "0.0.0-alpha.114",
|
|
295
295
|
"dependencies": [
|
|
296
|
+
"@agimon-ai/po-autostop",
|
|
296
297
|
"@agimon-ai/po-core"
|
|
297
298
|
]
|
|
298
299
|
},
|
|
299
300
|
"@agimon-ai/po-plan": {
|
|
300
|
-
"version": "0.0.0-alpha.
|
|
301
|
+
"version": "0.0.0-alpha.114",
|
|
301
302
|
"dependencies": [
|
|
302
303
|
"@agimon-ai/po-config",
|
|
303
304
|
"@agimon-ai/po-core",
|
|
@@ -307,7 +308,7 @@
|
|
|
307
308
|
]
|
|
308
309
|
},
|
|
309
310
|
"@agimon-ai/po-profile": {
|
|
310
|
-
"version": "0.0.0-alpha.
|
|
311
|
+
"version": "0.0.0-alpha.114",
|
|
311
312
|
"dependencies": [
|
|
312
313
|
"@agimon-ai/po-config",
|
|
313
314
|
"@agimon-ai/po-core",
|
|
@@ -315,7 +316,7 @@
|
|
|
315
316
|
]
|
|
316
317
|
},
|
|
317
318
|
"@agimon-ai/po-prompt": {
|
|
318
|
-
"version": "0.0.0-alpha.
|
|
319
|
+
"version": "0.0.0-alpha.114",
|
|
319
320
|
"dependencies": [
|
|
320
321
|
"@agimon-ai/po-core",
|
|
321
322
|
"@agimon-ai/po-web-components",
|
|
@@ -323,7 +324,7 @@
|
|
|
323
324
|
]
|
|
324
325
|
},
|
|
325
326
|
"@agimon-ai/po-read": {
|
|
326
|
-
"version": "0.0.0-alpha.
|
|
327
|
+
"version": "0.0.0-alpha.114",
|
|
327
328
|
"dependencies": [
|
|
328
329
|
"@agimon-ai/po-config",
|
|
329
330
|
"@agimon-ai/po-core",
|
|
@@ -333,7 +334,7 @@
|
|
|
333
334
|
]
|
|
334
335
|
},
|
|
335
336
|
"@agimon-ai/po-runner": {
|
|
336
|
-
"version": "0.0.0-alpha.
|
|
337
|
+
"version": "0.0.0-alpha.114",
|
|
337
338
|
"dependencies": [
|
|
338
339
|
"@agimon-ai/po-core",
|
|
339
340
|
"@agimon-ai/po-ui",
|
|
@@ -342,13 +343,13 @@
|
|
|
342
343
|
]
|
|
343
344
|
},
|
|
344
345
|
"@agimon-ai/po-sandbox": {
|
|
345
|
-
"version": "0.0.0-alpha.
|
|
346
|
+
"version": "0.0.0-alpha.114",
|
|
346
347
|
"dependencies": [
|
|
347
348
|
"@agimon-ai/po-core"
|
|
348
349
|
]
|
|
349
350
|
},
|
|
350
351
|
"@agimon-ai/po-session": {
|
|
351
|
-
"version": "0.0.0-alpha.
|
|
352
|
+
"version": "0.0.0-alpha.114",
|
|
352
353
|
"dependencies": [
|
|
353
354
|
"@agimon-ai/po-config",
|
|
354
355
|
"@agimon-ai/po-core",
|
|
@@ -356,7 +357,7 @@
|
|
|
356
357
|
]
|
|
357
358
|
},
|
|
358
359
|
"@agimon-ai/po-skill": {
|
|
359
|
-
"version": "0.0.0-alpha.
|
|
360
|
+
"version": "0.0.0-alpha.114",
|
|
360
361
|
"dependencies": [
|
|
361
362
|
"@agimon-ai/po-config",
|
|
362
363
|
"@agimon-ai/po-core",
|
|
@@ -365,7 +366,7 @@
|
|
|
365
366
|
]
|
|
366
367
|
},
|
|
367
368
|
"@agimon-ai/po-style-system": {
|
|
368
|
-
"version": "0.0.0-alpha.
|
|
369
|
+
"version": "0.0.0-alpha.114",
|
|
369
370
|
"dependencies": [
|
|
370
371
|
"@agimon-ai/po-core",
|
|
371
372
|
"@agimon-ai/po-web-components",
|
|
@@ -373,7 +374,7 @@
|
|
|
373
374
|
]
|
|
374
375
|
},
|
|
375
376
|
"@agimon-ai/po-task": {
|
|
376
|
-
"version": "0.0.0-alpha.
|
|
377
|
+
"version": "0.0.0-alpha.114",
|
|
377
378
|
"dependencies": [
|
|
378
379
|
"@agimon-ai/po-core",
|
|
379
380
|
"@agimon-ai/po-ui",
|
|
@@ -381,7 +382,7 @@
|
|
|
381
382
|
]
|
|
382
383
|
},
|
|
383
384
|
"@agimon-ai/po-team": {
|
|
384
|
-
"version": "0.0.0-alpha.
|
|
385
|
+
"version": "0.0.0-alpha.114",
|
|
385
386
|
"dependencies": [
|
|
386
387
|
"@agimon-ai/po-cache",
|
|
387
388
|
"@agimon-ai/po-config",
|
|
@@ -393,7 +394,7 @@
|
|
|
393
394
|
]
|
|
394
395
|
},
|
|
395
396
|
"@agimon-ai/po-template-advanced": {
|
|
396
|
-
"version": "0.0.0-alpha.
|
|
397
|
+
"version": "0.0.0-alpha.114",
|
|
397
398
|
"dependencies": [
|
|
398
399
|
"@agimon-ai/po-core",
|
|
399
400
|
"@agimon-ai/po-web-components",
|
|
@@ -401,7 +402,7 @@
|
|
|
401
402
|
]
|
|
402
403
|
},
|
|
403
404
|
"@agimon-ai/po-template-elegant": {
|
|
404
|
-
"version": "0.0.0-alpha.
|
|
405
|
+
"version": "0.0.0-alpha.114",
|
|
405
406
|
"dependencies": [
|
|
406
407
|
"@agimon-ai/po-core",
|
|
407
408
|
"@agimon-ai/po-web-components",
|
|
@@ -409,7 +410,7 @@
|
|
|
409
410
|
]
|
|
410
411
|
},
|
|
411
412
|
"@agimon-ai/po-ui": {
|
|
412
|
-
"version": "0.0.0-alpha.
|
|
413
|
+
"version": "0.0.0-alpha.114",
|
|
413
414
|
"dependencies": [
|
|
414
415
|
"@agimon-ai/po-core",
|
|
415
416
|
"@agimon-ai/po-hashline",
|
|
@@ -418,7 +419,7 @@
|
|
|
418
419
|
]
|
|
419
420
|
},
|
|
420
421
|
"@agimon-ai/po-user-feedback": {
|
|
421
|
-
"version": "0.0.0-alpha.
|
|
422
|
+
"version": "0.0.0-alpha.114",
|
|
422
423
|
"dependencies": [
|
|
423
424
|
"@agimon-ai/po-core",
|
|
424
425
|
"@agimon-ai/po-minor-mode",
|
|
@@ -427,7 +428,7 @@
|
|
|
427
428
|
]
|
|
428
429
|
},
|
|
429
430
|
"@agimon-ai/po-vault": {
|
|
430
|
-
"version": "0.0.0-alpha.
|
|
431
|
+
"version": "0.0.0-alpha.114",
|
|
431
432
|
"dependencies": [
|
|
432
433
|
"@agimon-ai/po-core",
|
|
433
434
|
"@agimon-ai/po-db",
|
|
@@ -436,7 +437,7 @@
|
|
|
436
437
|
]
|
|
437
438
|
},
|
|
438
439
|
"@agimon-ai/po-vibe-lint": {
|
|
439
|
-
"version": "0.0.1-alpha.
|
|
440
|
+
"version": "0.0.1-alpha.83",
|
|
440
441
|
"dependencies": [
|
|
441
442
|
"@agimon-ai/po-config",
|
|
442
443
|
"@agimon-ai/po-core",
|
|
@@ -446,11 +447,12 @@
|
|
|
446
447
|
]
|
|
447
448
|
},
|
|
448
449
|
"@agimon-ai/po-voice": {
|
|
449
|
-
"version": "0.0.0-alpha.
|
|
450
|
+
"version": "0.0.0-alpha.114",
|
|
450
451
|
"dependencies": [
|
|
451
452
|
"@agimon-ai/po-config",
|
|
452
453
|
"@agimon-ai/po-core",
|
|
453
454
|
"@agimon-ai/po-minor-mode",
|
|
455
|
+
"@agimon-ai/po-notification",
|
|
454
456
|
"@agimon-ai/po-session",
|
|
455
457
|
"@agimon-ai/po-ui",
|
|
456
458
|
"@agimon-ai/po-web-components",
|
|
@@ -458,11 +460,11 @@
|
|
|
458
460
|
]
|
|
459
461
|
},
|
|
460
462
|
"@agimon-ai/po-web-components": {
|
|
461
|
-
"version": "0.0.0-alpha.
|
|
463
|
+
"version": "0.0.0-alpha.114",
|
|
462
464
|
"dependencies": []
|
|
463
465
|
},
|
|
464
466
|
"@agimon-ai/po-web-dashboard": {
|
|
465
|
-
"version": "0.0.0-alpha.
|
|
467
|
+
"version": "0.0.0-alpha.114",
|
|
466
468
|
"dependencies": [
|
|
467
469
|
"@agimon-ai/po-core",
|
|
468
470
|
"@agimon-ai/po-web-components",
|
|
@@ -470,18 +472,18 @@
|
|
|
470
472
|
]
|
|
471
473
|
},
|
|
472
474
|
"@agimon-ai/po-web-search": {
|
|
473
|
-
"version": "0.0.0-alpha.
|
|
475
|
+
"version": "0.0.0-alpha.113",
|
|
474
476
|
"dependencies": [
|
|
475
477
|
"@agimon-ai/po-core",
|
|
476
478
|
"@agimon-ai/po-web-components"
|
|
477
479
|
]
|
|
478
480
|
},
|
|
479
481
|
"@agimon-ai/po-web-security": {
|
|
480
|
-
"version": "0.0.0-alpha.
|
|
482
|
+
"version": "0.0.0-alpha.114",
|
|
481
483
|
"dependencies": []
|
|
482
484
|
},
|
|
483
485
|
"@agimon-ai/po-workflow": {
|
|
484
|
-
"version": "0.0.0-alpha.
|
|
486
|
+
"version": "0.0.0-alpha.114",
|
|
485
487
|
"dependencies": [
|
|
486
488
|
"@agimon-ai/po-core",
|
|
487
489
|
"@agimon-ai/po-ui",
|
package/dist/package.cjs
CHANGED
package/dist/package.mjs
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
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");
|
|
4
3
|
let _agimon_ai_po_core_notification = require("@agimon-ai/po-core/notification");
|
|
5
4
|
let _agimon_ai_po_notification = require("@agimon-ai/po-notification");
|
|
6
|
-
let _agimon_ai_po_autostop = require("@agimon-ai/po-autostop");
|
|
7
5
|
//#region src/builders/server/nativePush.ts
|
|
8
6
|
const MAX_CREDENTIAL_BYTES = 65536;
|
|
9
7
|
const FANOUT = 4;
|
|
@@ -117,17 +115,15 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
117
115
|
try {
|
|
118
116
|
const state = await hub.sessionService.readExecutionState?.(sessionId);
|
|
119
117
|
if (!current() || remote.state().status !== "on") return;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
held
|
|
125
|
-
later(sessionId, held, run, _agimon_ai_po_autostop.DEFAULT_AUTO_STOP_DELAYS.cooldownMs);
|
|
118
|
+
const decision = (0, _agimon_ai_po_notification.decideSessionFinished)(state, held.holdingSince, Date.now());
|
|
119
|
+
if (decision.action === "unavailable") throw new Error("Execution state unavailable");
|
|
120
|
+
if (decision.action === "hold") {
|
|
121
|
+
held.holdingSince = decision.holdingSince;
|
|
122
|
+
later(sessionId, held, run, decision.delayMs);
|
|
126
123
|
return;
|
|
127
124
|
}
|
|
128
|
-
|
|
129
|
-
if (decision.action ===
|
|
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)({
|
|
125
|
+
if (decision.action === "recheck") later(sessionId, held, run, decision.delayMs);
|
|
126
|
+
else if (decision.action === "finished") enqueue((0, _agimon_ai_po_core_notification.createPoNotificationEntryData)((0, _agimon_ai_po_notification.settledNotification)({
|
|
131
127
|
cwd: held.session.cwd,
|
|
132
128
|
sessionName: held.session.name
|
|
133
129
|
})), sessionId);
|
|
@@ -158,7 +154,7 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
158
154
|
held.dialogs.clear();
|
|
159
155
|
} else if (session.phase === "idle" && held.running) {
|
|
160
156
|
held.running = false;
|
|
161
|
-
later(session.id, held, held.run,
|
|
157
|
+
later(session.id, held, held.run, _agimon_ai_po_notification.SESSION_FINISHED_COOLDOWN_MS);
|
|
162
158
|
}
|
|
163
159
|
};
|
|
164
160
|
for (const session of hub.snapshot()) track(session);
|
|
@@ -1 +1 @@
|
|
|
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","PO_NOTIFICATION_ENTRY_TYPE","isPoNotificationEntryData","notificationBody","attentionNotification"],"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 {\n createPoNotificationEntryData,\n isPoNotificationEntryData,\n PO_NOTIFICATION_ENTRY_TYPE,\n} 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 // Attention notices are the exception: the person must act (an approval), so every session pushes.\n if (event.kind === 'frame' && event.frame.type === 'entry_appended') {\n const entry = event.frame.entry as { customType?: unknown; data?: unknown } | undefined;\n if (\n entry?.customType === PO_NOTIFICATION_ENTRY_TYPE &&\n isPoNotificationEntryData(entry.data) &&\n entry.data.attention\n )\n enqueue(\n {\n ...entry.data,\n body: notificationBody(entry.data.body),\n subtitle: tracked.get(event.sessionId)?.session.name ?? entry.data.subtitle,\n },\n event.sessionId,\n );\n return;\n }\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
|
+
{"version":3,"file":"nativePush.cjs","names":["readBoundedFile","BACKGROUND_CONTEXT","createPrivateKey","decideSessionFinished","createPoNotificationEntryData","settledNotification","SESSION_FINISHED_COOLDOWN_MS","PO_NOTIFICATION_ENTRY_TYPE","isPoNotificationEntryData","notificationBody","attentionNotification"],"sources":["../../../../src/builders/server/nativePush.ts"],"sourcesContent":["import { createPrivateKey } from 'node:crypto';\n\nimport type { HeadlessHub } from '@agimon-ai/po-core/headlessHub';\nimport {\n createPoNotificationEntryData,\n isPoNotificationEntryData,\n PO_NOTIFICATION_ENTRY_TYPE,\n} 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 decideSessionFinished,\n notificationBody,\n SESSION_FINISHED_COOLDOWN_MS,\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 const decision = decideSessionFinished(state, held.holdingSince, Date.now());\n if (decision.action === 'unavailable') throw new Error('Execution state unavailable');\n if (decision.action === 'hold') {\n held.holdingSince = decision.holdingSince;\n later(sessionId, held, run, decision.delayMs);\n return;\n }\n if (decision.action === 'recheck') later(sessionId, held, run, decision.delayMs);\n else if (decision.action === 'finished')\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, SESSION_FINISHED_COOLDOWN_MS);\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 // Attention notices are the exception: the person must act (an approval), so every session pushes.\n if (event.kind === 'frame' && event.frame.type === 'entry_appended') {\n const entry = event.frame.entry as { customType?: unknown; data?: unknown } | undefined;\n if (\n entry?.customType === PO_NOTIFICATION_ENTRY_TYPE &&\n isPoNotificationEntryData(entry.data) &&\n entry.data.attention\n )\n enqueue(\n {\n ...entry.data,\n body: notificationBody(entry.data.body),\n subtitle: tracked.get(event.sessionId)?.session.name ?? entry.data.subtitle,\n },\n event.sessionId,\n );\n return;\n }\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,9 +1,7 @@
|
|
|
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";
|
|
4
3
|
import { PO_NOTIFICATION_ENTRY_TYPE, createPoNotificationEntryData, isPoNotificationEntryData } from "@agimon-ai/po-core/notification";
|
|
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";
|
|
4
|
+
import { SESSION_FINISHED_COOLDOWN_MS, attentionNotification, decideSessionFinished, notificationBody, settledNotification } from "@agimon-ai/po-notification";
|
|
7
5
|
//#region src/builders/server/nativePush.ts
|
|
8
6
|
const MAX_CREDENTIAL_BYTES = 65536;
|
|
9
7
|
const FANOUT = 4;
|
|
@@ -117,17 +115,15 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
117
115
|
try {
|
|
118
116
|
const state = await hub.sessionService.readExecutionState?.(sessionId);
|
|
119
117
|
if (!current() || remote.state().status !== "on") return;
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
held
|
|
125
|
-
later(sessionId, held, run, DEFAULT_AUTO_STOP_DELAYS.cooldownMs);
|
|
118
|
+
const decision = decideSessionFinished(state, held.holdingSince, Date.now());
|
|
119
|
+
if (decision.action === "unavailable") throw new Error("Execution state unavailable");
|
|
120
|
+
if (decision.action === "hold") {
|
|
121
|
+
held.holdingSince = decision.holdingSince;
|
|
122
|
+
later(sessionId, held, run, decision.delayMs);
|
|
126
123
|
return;
|
|
127
124
|
}
|
|
128
|
-
|
|
129
|
-
if (decision.action ===
|
|
130
|
-
else if (decision.action === AUTO_STOP_ACTION.shutdown) enqueue(createPoNotificationEntryData(settledNotification({
|
|
125
|
+
if (decision.action === "recheck") later(sessionId, held, run, decision.delayMs);
|
|
126
|
+
else if (decision.action === "finished") enqueue(createPoNotificationEntryData(settledNotification({
|
|
131
127
|
cwd: held.session.cwd,
|
|
132
128
|
sessionName: held.session.name
|
|
133
129
|
})), sessionId);
|
|
@@ -158,7 +154,7 @@ function subscribeNativePush(hub, remote, sender, notice) {
|
|
|
158
154
|
held.dialogs.clear();
|
|
159
155
|
} else if (session.phase === "idle" && held.running) {
|
|
160
156
|
held.running = false;
|
|
161
|
-
later(session.id, held, held.run,
|
|
157
|
+
later(session.id, held, held.run, SESSION_FINISHED_COOLDOWN_MS);
|
|
162
158
|
}
|
|
163
159
|
};
|
|
164
160
|
for (const session of hub.snapshot()) track(session);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"nativePush.mjs","names":[],"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 {\n createPoNotificationEntryData,\n isPoNotificationEntryData,\n PO_NOTIFICATION_ENTRY_TYPE,\n} 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 // Attention notices are the exception: the person must act (an approval), so every session pushes.\n if (event.kind === 'frame' && event.frame.type === 'entry_appended') {\n const entry = event.frame.entry as { customType?: unknown; data?: unknown } | undefined;\n if (\n entry?.customType === PO_NOTIFICATION_ENTRY_TYPE &&\n isPoNotificationEntryData(entry.data) &&\n entry.data.attention\n )\n enqueue(\n {\n ...entry.data,\n body: notificationBody(entry.data.body),\n subtitle: tracked.get(event.sessionId)?.session.name ?? entry.data.subtitle,\n },\n event.sessionId,\n );\n return;\n }\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
|
+
{"version":3,"file":"nativePush.mjs","names":[],"sources":["../../../../src/builders/server/nativePush.ts"],"sourcesContent":["import { createPrivateKey } from 'node:crypto';\n\nimport type { HeadlessHub } from '@agimon-ai/po-core/headlessHub';\nimport {\n createPoNotificationEntryData,\n isPoNotificationEntryData,\n PO_NOTIFICATION_ENTRY_TYPE,\n} 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 decideSessionFinished,\n notificationBody,\n SESSION_FINISHED_COOLDOWN_MS,\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 const decision = decideSessionFinished(state, held.holdingSince, Date.now());\n if (decision.action === 'unavailable') throw new Error('Execution state unavailable');\n if (decision.action === 'hold') {\n held.holdingSince = decision.holdingSince;\n later(sessionId, held, run, decision.delayMs);\n return;\n }\n if (decision.action === 'recheck') later(sessionId, held, run, decision.delayMs);\n else if (decision.action === 'finished')\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, SESSION_FINISHED_COOLDOWN_MS);\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 // Attention notices are the exception: the person must act (an approval), so every session pushes.\n if (event.kind === 'frame' && event.frame.type === 'entry_appended') {\n const entry = event.frame.entry as { customType?: unknown; data?: unknown } | undefined;\n if (\n entry?.customType === PO_NOTIFICATION_ENTRY_TYPE &&\n isPoNotificationEntryData(entry.data) &&\n entry.data.attention\n )\n enqueue(\n {\n ...entry.data,\n body: notificationBody(entry.data.body),\n subtitle: tracked.get(event.sessionId)?.session.name ?? entry.data.subtitle,\n },\n event.sessionId,\n );\n return;\n }\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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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@agimon-ai/po",
|
|
3
|
-
"version": "0.0.0-alpha.
|
|
3
|
+
"version": "0.0.0-alpha.115",
|
|
4
4
|
"description": "Opinionated, composable agent harness for scoped tools, skills, MCP servers, and developer workflows.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"agent-harness",
|
|
@@ -177,28 +177,28 @@
|
|
|
177
177
|
"registry": "https://registry.npmjs.org/"
|
|
178
178
|
},
|
|
179
179
|
"dependencies": {
|
|
180
|
-
"@agimon-ai/po-approval": "0.0.0-alpha.
|
|
181
|
-
"@agimon-ai/po-artifact": "0.0.0-alpha.
|
|
182
|
-
"@agimon-ai/po-autostop": "0.0.0-alpha.
|
|
183
|
-
"@agimon-ai/po-cache": "0.0.0-alpha.
|
|
184
|
-
"@agimon-ai/po-config": "0.0.0-alpha.
|
|
185
|
-
"@agimon-ai/po-core": "0.0.0-alpha.
|
|
186
|
-
"@agimon-ai/po-db": "0.0.0-alpha.
|
|
187
|
-
"@agimon-ai/po-domain": "0.0.0-alpha.
|
|
188
|
-
"@agimon-ai/po-logsink": "0.0.1-alpha.
|
|
189
|
-
"@agimon-ai/po-major-mode": "0.0.0-alpha.
|
|
190
|
-
"@agimon-ai/po-mcp-proxy": "0.0.1-alpha.
|
|
191
|
-
"@agimon-ai/po-minor-mode": "0.0.0-alpha.
|
|
192
|
-
"@agimon-ai/po-native-components": "0.0.0-alpha.
|
|
193
|
-
"@agimon-ai/po-network": "0.0.2-alpha.
|
|
194
|
-
"@agimon-ai/po-notification": "0.0.0-alpha.
|
|
195
|
-
"@agimon-ai/po-profile": "0.0.0-alpha.
|
|
196
|
-
"@agimon-ai/po-session": "0.0.0-alpha.
|
|
197
|
-
"@agimon-ai/po-skill": "0.0.0-alpha.
|
|
198
|
-
"@agimon-ai/po-ui": "0.0.0-alpha.
|
|
199
|
-
"@agimon-ai/po-vault": "0.0.0-alpha.
|
|
200
|
-
"@agimon-ai/po-web-components": "0.0.0-alpha.
|
|
201
|
-
"@agimon-ai/po-web-security": "0.0.0-alpha.
|
|
180
|
+
"@agimon-ai/po-approval": "0.0.0-alpha.114",
|
|
181
|
+
"@agimon-ai/po-artifact": "0.0.0-alpha.113",
|
|
182
|
+
"@agimon-ai/po-autostop": "0.0.0-alpha.114",
|
|
183
|
+
"@agimon-ai/po-cache": "0.0.0-alpha.114",
|
|
184
|
+
"@agimon-ai/po-config": "0.0.0-alpha.114",
|
|
185
|
+
"@agimon-ai/po-core": "0.0.0-alpha.114",
|
|
186
|
+
"@agimon-ai/po-db": "0.0.0-alpha.114",
|
|
187
|
+
"@agimon-ai/po-domain": "0.0.0-alpha.114",
|
|
188
|
+
"@agimon-ai/po-logsink": "0.0.1-alpha.96",
|
|
189
|
+
"@agimon-ai/po-major-mode": "0.0.0-alpha.114",
|
|
190
|
+
"@agimon-ai/po-mcp-proxy": "0.0.1-alpha.93",
|
|
191
|
+
"@agimon-ai/po-minor-mode": "0.0.0-alpha.114",
|
|
192
|
+
"@agimon-ai/po-native-components": "0.0.0-alpha.114",
|
|
193
|
+
"@agimon-ai/po-network": "0.0.2-alpha.61",
|
|
194
|
+
"@agimon-ai/po-notification": "0.0.0-alpha.114",
|
|
195
|
+
"@agimon-ai/po-profile": "0.0.0-alpha.114",
|
|
196
|
+
"@agimon-ai/po-session": "0.0.0-alpha.114",
|
|
197
|
+
"@agimon-ai/po-skill": "0.0.0-alpha.114",
|
|
198
|
+
"@agimon-ai/po-ui": "0.0.0-alpha.114",
|
|
199
|
+
"@agimon-ai/po-vault": "0.0.0-alpha.114",
|
|
200
|
+
"@agimon-ai/po-web-components": "0.0.0-alpha.114",
|
|
201
|
+
"@agimon-ai/po-web-security": "0.0.0-alpha.114",
|
|
202
202
|
"@deepseek-ai/cordis": "4.0.5",
|
|
203
203
|
"@earendil-works/pi-agent-core": "1.5.0",
|
|
204
204
|
"@earendil-works/pi-coding-agent": "1.5.0",
|
|
@@ -220,10 +220,10 @@
|
|
|
220
220
|
"yaml": "2.9.1"
|
|
221
221
|
},
|
|
222
222
|
"devDependencies": {
|
|
223
|
-
"@agimon-ai/po-calendar": "0.0.1-alpha.
|
|
224
|
-
"@agimon-ai/po-identity": "0.0.2-alpha.
|
|
225
|
-
"@agimon-ai/po-runner": "0.0.0-alpha.
|
|
226
|
-
"@agimon-ai/vibe-lint-plugin-po-cli": "0.0.0-alpha.
|
|
223
|
+
"@agimon-ai/po-calendar": "0.0.1-alpha.73",
|
|
224
|
+
"@agimon-ai/po-identity": "0.0.2-alpha.61",
|
|
225
|
+
"@agimon-ai/po-runner": "0.0.0-alpha.114",
|
|
226
|
+
"@agimon-ai/vibe-lint-plugin-po-cli": "0.0.0-alpha.114",
|
|
227
227
|
"@earendil-works/pi-ai": "1.5.0",
|
|
228
228
|
"@modelcontextprotocol/ext-apps": "2.0.3",
|
|
229
229
|
"@modelcontextprotocol/server": "2.3.1",
|