@sebastianandreasson/pi-autonomous-agents 0.5.1 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +23 -8
- package/SETUP.md +5 -0
- package/docs/PI_SUPERVISOR.md +14 -64
- package/package.json +6 -3
- package/pi.config.json +1 -2
- package/src/cli.mjs +50 -2
- package/src/index.mjs +2 -0
- package/src/pi-client.mjs +68 -119
- package/src/pi-config.mjs +3 -3
- package/src/pi-repo.mjs +92 -11
- package/src/pi-sdk-turn.mjs +654 -0
- package/src/pi-supervisor.mjs +85 -4
- package/src/pi-telemetry.mjs +4 -0
- package/src/pi-visualizer-shared.mjs +219 -0
- package/src/pi-visualizer.mjs +476 -0
- package/templates/pi.config.example.json +1 -2
- package/src/pi-rpc-adapter.mjs +0 -606
package/src/pi-repo.mjs
CHANGED
|
@@ -114,6 +114,57 @@ export function isProcessRunning(pid) {
|
|
|
114
114
|
}
|
|
115
115
|
}
|
|
116
116
|
|
|
117
|
+
const ownedChildren = new Map()
|
|
118
|
+
|
|
119
|
+
export function registerOwnedChildProcess(child, options = {}) {
|
|
120
|
+
const pid = normalizePid(child?.pid)
|
|
121
|
+
if (pid <= 0) {
|
|
122
|
+
return () => {}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const entry = {
|
|
126
|
+
useProcessGroup: options.useProcessGroup === true && process.platform !== 'win32',
|
|
127
|
+
}
|
|
128
|
+
ownedChildren.set(pid, entry)
|
|
129
|
+
|
|
130
|
+
const unregister = () => {
|
|
131
|
+
ownedChildren.delete(pid)
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
if (typeof child?.once === 'function') {
|
|
135
|
+
child.once('exit', unregister)
|
|
136
|
+
child.once('close', unregister)
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return unregister
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
export function signalChildProcess(pid, signal, options = {}) {
|
|
143
|
+
const normalizedPid = normalizePid(pid)
|
|
144
|
+
if (normalizedPid <= 0) {
|
|
145
|
+
return false
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
try {
|
|
149
|
+
if (options.useProcessGroup === true && process.platform !== 'win32') {
|
|
150
|
+
process.kill(-normalizedPid, signal)
|
|
151
|
+
} else {
|
|
152
|
+
process.kill(normalizedPid, signal)
|
|
153
|
+
}
|
|
154
|
+
return true
|
|
155
|
+
} catch {
|
|
156
|
+
return false
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export function signalOwnedChildProcesses(signal) {
|
|
161
|
+
let handled = false
|
|
162
|
+
for (const [pid, entry] of [...ownedChildren.entries()]) {
|
|
163
|
+
handled = signalChildProcess(pid, signal, entry) || handled
|
|
164
|
+
}
|
|
165
|
+
return handled
|
|
166
|
+
}
|
|
167
|
+
|
|
117
168
|
export async function readJsonFile(filePath, fallback = null) {
|
|
118
169
|
try {
|
|
119
170
|
const raw = await fs.readFile(filePath, 'utf8')
|
|
@@ -211,20 +262,45 @@ export async function releaseRunLock(lockFile, runId) {
|
|
|
211
262
|
}
|
|
212
263
|
|
|
213
264
|
export function signalProcessTree(pid, signal) {
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
265
|
+
return signalChildProcess(pid, signal, { useProcessGroup: true })
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
export function watchParentProcess(onParentExit, options = {}) {
|
|
269
|
+
const expectedParentPid = normalizePid(options.parentPid ?? process.ppid)
|
|
270
|
+
if (expectedParentPid <= 0 || typeof onParentExit !== 'function') {
|
|
271
|
+
return () => {}
|
|
217
272
|
}
|
|
218
273
|
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
274
|
+
let active = true
|
|
275
|
+
const intervalMs = Number.isFinite(Number(options.intervalMs))
|
|
276
|
+
? Math.max(100, Number(options.intervalMs))
|
|
277
|
+
: 1000
|
|
278
|
+
|
|
279
|
+
const interval = setInterval(() => {
|
|
280
|
+
if (!active) {
|
|
281
|
+
return
|
|
224
282
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
283
|
+
|
|
284
|
+
const currentParentPid = normalizePid(process.ppid)
|
|
285
|
+
if (currentParentPid === expectedParentPid && currentParentPid > 1) {
|
|
286
|
+
return
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
active = false
|
|
290
|
+
clearInterval(interval)
|
|
291
|
+
onParentExit({
|
|
292
|
+
expectedParentPid,
|
|
293
|
+
currentParentPid,
|
|
294
|
+
})
|
|
295
|
+
}, intervalMs)
|
|
296
|
+
|
|
297
|
+
if (typeof interval.unref === 'function') {
|
|
298
|
+
interval.unref()
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return () => {
|
|
302
|
+
active = false
|
|
303
|
+
clearInterval(interval)
|
|
228
304
|
}
|
|
229
305
|
}
|
|
230
306
|
|
|
@@ -474,6 +550,9 @@ export async function runShellCommand({
|
|
|
474
550
|
detached: process.platform !== 'win32',
|
|
475
551
|
stdio: ['pipe', 'pipe', 'pipe'],
|
|
476
552
|
})
|
|
553
|
+
const unregisterChild = registerOwnedChildProcess(child, {
|
|
554
|
+
useProcessGroup: process.platform !== 'win32',
|
|
555
|
+
})
|
|
477
556
|
|
|
478
557
|
let stdout = ''
|
|
479
558
|
let stderr = ''
|
|
@@ -506,6 +585,7 @@ export async function runShellCommand({
|
|
|
506
585
|
})
|
|
507
586
|
|
|
508
587
|
child.on('error', (error) => {
|
|
588
|
+
unregisterChild()
|
|
509
589
|
if (killTimer) {
|
|
510
590
|
clearTimeout(killTimer)
|
|
511
591
|
}
|
|
@@ -524,6 +604,7 @@ export async function runShellCommand({
|
|
|
524
604
|
})
|
|
525
605
|
|
|
526
606
|
child.on('close', (code) => {
|
|
607
|
+
unregisterChild()
|
|
527
608
|
if (killTimer) {
|
|
528
609
|
clearTimeout(killTimer)
|
|
529
610
|
}
|