@sebastianandreasson/pi-autonomous-agents 0.14.0 → 0.14.1

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 CHANGED
@@ -80,7 +80,7 @@ Typical scripts:
80
80
 
81
81
  Start from [templates/pi.config.example.json](./templates/pi.config.example.json), [templates/DEVELOPER.md](./templates/DEVELOPER.md), [templates/TESTER.md](./templates/TESTER.md), and [templates/gitignore.fragment](./templates/gitignore.fragment).
82
82
 
83
- Request telemetry is enabled by default for SDK runs. `pi-harness` writes a managed Pi extension shim to `.pi/extensions/pi-harness-request-telemetry/index.mjs` in the consuming repo, and Pi auto-discovers it on the next resource reload. Disable that with `PI_REQUEST_TELEMETRY_ENABLED=0` or `"piRequestTelemetryEnabled": false`.
83
+ Request telemetry is enabled by default for SDK runs. `pi-harness` writes a managed Pi extension package under `.pi/extensions/pi-harness-request-telemetry/` in the consuming repo, with a `package.json` manifest and `index.mjs` shim that Pi auto-discovers on the next resource reload. Disable that with `PI_REQUEST_TELEMETRY_ENABLED=0` or `"piRequestTelemetryEnabled": false`.
84
84
 
85
85
  ## CLI
86
86
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  This document describes the repo-local Pi extension prototype under [pi-extensions/request-telemetry](../pi-extensions/request-telemetry/README.md).
4
4
 
5
- In normal `pi-harness` SDK runs, this extension is auto-enabled by installing a managed shim under `.pi/extensions/pi-harness-request-telemetry/` in the consuming repo before Pi reloads resources. Opt out with `PI_REQUEST_TELEMETRY_ENABLED=0` or `"piRequestTelemetryEnabled": false`.
5
+ In normal `pi-harness` SDK runs, this extension is auto-enabled by installing a managed extension package under `.pi/extensions/pi-harness-request-telemetry/` in the consuming repo before Pi reloads resources. That package contains a `package.json` Pi manifest plus the generated `index.mjs` shim. Opt out with `PI_REQUEST_TELEMETRY_ENABLED=0` or `"piRequestTelemetryEnabled": false`.
6
6
 
7
7
  The purpose of this extension is to gather request-level data directly from Pi extension hooks before we decide whether to patch `@mariozechner/pi-coding-agent` or `pi-ai`.
8
8
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sebastianandreasson/pi-autonomous-agents",
3
3
  "private": false,
4
- "version": "0.14.0",
4
+ "version": "0.14.1",
5
5
  "type": "module",
6
6
  "description": "Portable unattended PI harness for developer/tester/visual-review loops.",
7
7
  "license": "MIT",
@@ -761,6 +761,7 @@ export function getManagedRequestTelemetryExtensionPaths({ cwd } = {}) {
761
761
  extensionRoot,
762
762
  extensionDir,
763
763
  entryFile: path.join(extensionDir, 'index.mjs'),
764
+ manifestFile: path.join(extensionDir, 'package.json'),
764
765
  sourceFile: bundledRequestTelemetryExtensionFile,
765
766
  }
766
767
  }
@@ -775,6 +776,17 @@ function renderRequestTelemetryExtensionShim(sourceFile) {
775
776
  ].join('\n')
776
777
  }
777
778
 
779
+ function renderRequestTelemetryExtensionManifest() {
780
+ return `${JSON.stringify({
781
+ name: REQUEST_TELEMETRY_EXTENSION_DIRNAME,
782
+ private: true,
783
+ type: 'module',
784
+ pi: {
785
+ extensions: ['./index.mjs'],
786
+ },
787
+ }, null, 2)}\n`
788
+ }
789
+
778
790
  export async function ensureBundledRequestTelemetryExtension({ cwd, enabled = true } = {}) {
779
791
  const paths = getManagedRequestTelemetryExtensionPaths({ cwd })
780
792
 
@@ -792,15 +804,23 @@ export async function ensureBundledRequestTelemetryExtension({ cwd, enabled = tr
792
804
  await fs.access(paths.sourceFile)
793
805
  await fs.mkdir(paths.extensionDir, { recursive: true })
794
806
 
795
- const content = renderRequestTelemetryExtensionShim(paths.sourceFile)
796
- let existing = ''
807
+ const entryContent = renderRequestTelemetryExtensionShim(paths.sourceFile)
808
+ const manifestContent = renderRequestTelemetryExtensionManifest()
809
+ let existingEntry = ''
810
+ let existingManifest = ''
797
811
  try {
798
- existing = await fs.readFile(paths.entryFile, 'utf8')
812
+ existingEntry = await fs.readFile(paths.entryFile, 'utf8')
813
+ } catch {}
814
+ try {
815
+ existingManifest = await fs.readFile(paths.manifestFile, 'utf8')
799
816
  } catch {}
800
817
 
801
- const updated = existing !== content
802
- if (updated) {
803
- await fs.writeFile(paths.entryFile, content, 'utf8')
818
+ const updated = existingEntry !== entryContent || existingManifest !== manifestContent
819
+ if (existingEntry !== entryContent) {
820
+ await fs.writeFile(paths.entryFile, entryContent, 'utf8')
821
+ }
822
+ if (existingManifest !== manifestContent) {
823
+ await fs.writeFile(paths.manifestFile, manifestContent, 'utf8')
804
824
  }
805
825
 
806
826
  return {
@@ -445,6 +445,7 @@ npm run dev:visualizer:ui</pre>
445
445
  export async function startVisualizerServer(config, overrides = {}) {
446
446
  const host = String(overrides.host ?? readVisualizerHost()).trim() || '127.0.0.1'
447
447
  const port = Number.isFinite(Number(overrides.port)) ? Number(overrides.port) : readVisualizerPort()
448
+ const sockets = new Set()
448
449
 
449
450
  const server = http.createServer(async (req, res) => {
450
451
  try {
@@ -494,6 +495,13 @@ export async function startVisualizerServer(config, overrides = {}) {
494
495
  }
495
496
  })
496
497
 
498
+ server.on('connection', (socket) => {
499
+ sockets.add(socket)
500
+ socket.on('close', () => {
501
+ sockets.delete(socket)
502
+ })
503
+ })
504
+
497
505
  await new Promise((resolve, reject) => {
498
506
  server.once('error', reject)
499
507
  server.listen(port, host, () => {
@@ -509,14 +517,44 @@ export async function startVisualizerServer(config, overrides = {}) {
509
517
  port,
510
518
  url,
511
519
  async close() {
512
- await new Promise((resolve, reject) => {
520
+ await new Promise((resolve) => {
521
+ const finish = () => {
522
+ for (const socket of sockets) {
523
+ socket.destroy()
524
+ }
525
+ sockets.clear()
526
+ resolve()
527
+ }
528
+
529
+ const timeout = setTimeout(() => {
530
+ if (typeof server.closeIdleConnections === 'function') {
531
+ server.closeIdleConnections()
532
+ }
533
+ if (typeof server.closeAllConnections === 'function') {
534
+ server.closeAllConnections()
535
+ }
536
+ finish()
537
+ }, 1000)
538
+
513
539
  server.close((error) => {
540
+ clearTimeout(timeout)
514
541
  if (error) {
515
- reject(error)
542
+ finish()
516
543
  return
517
544
  }
518
- resolve()
545
+ finish()
519
546
  })
547
+
548
+ if (typeof server.closeIdleConnections === 'function') {
549
+ server.closeIdleConnections()
550
+ }
551
+ if (typeof server.closeAllConnections === 'function') {
552
+ server.closeAllConnections()
553
+ }
554
+
555
+ for (const socket of sockets) {
556
+ socket.end()
557
+ }
520
558
  })
521
559
  },
522
560
  }