jfl 0.4.4 → 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/dist/commands/context-hub.d.ts +1 -0
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +1064 -41
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/eval.d.ts +1 -1
- package/dist/commands/eval.d.ts.map +1 -1
- package/dist/commands/eval.js +192 -1
- package/dist/commands/eval.js.map +1 -1
- package/dist/commands/findings.d.ts +6 -0
- package/dist/commands/findings.d.ts.map +1 -0
- package/dist/commands/findings.js +203 -0
- package/dist/commands/findings.js.map +1 -0
- package/dist/commands/hud.d.ts.map +1 -1
- package/dist/commands/hud.js +47 -9
- package/dist/commands/hud.js.map +1 -1
- package/dist/commands/ide.d.ts +27 -0
- package/dist/commands/ide.d.ts.map +1 -0
- package/dist/commands/ide.js +546 -0
- package/dist/commands/ide.js.map +1 -0
- package/dist/commands/onboard.d.ts.map +1 -1
- package/dist/commands/onboard.js +212 -2
- package/dist/commands/onboard.js.map +1 -1
- package/dist/commands/openclaw.d.ts +3 -0
- package/dist/commands/openclaw.d.ts.map +1 -1
- package/dist/commands/openclaw.js +76 -2
- package/dist/commands/openclaw.js.map +1 -1
- package/dist/commands/peter.d.ts +3 -0
- package/dist/commands/peter.d.ts.map +1 -1
- package/dist/commands/peter.js +1168 -58
- package/dist/commands/peter.js.map +1 -1
- package/dist/commands/pi-fleet.d.ts +18 -0
- package/dist/commands/pi-fleet.d.ts.map +1 -0
- package/dist/commands/pi-fleet.js +382 -0
- package/dist/commands/pi-fleet.js.map +1 -0
- package/dist/commands/pi.d.ts.map +1 -1
- package/dist/commands/pi.js +18 -3
- package/dist/commands/pi.js.map +1 -1
- package/dist/commands/scope.d.ts.map +1 -1
- package/dist/commands/scope.js +90 -1
- package/dist/commands/scope.js.map +1 -1
- package/dist/commands/services.d.ts.map +1 -1
- package/dist/commands/services.js +18 -0
- package/dist/commands/services.js.map +1 -1
- package/dist/commands/setup.d.ts +12 -0
- package/dist/commands/setup.d.ts.map +1 -0
- package/dist/commands/setup.js +322 -0
- package/dist/commands/setup.js.map +1 -0
- package/dist/commands/status.d.ts.map +1 -1
- package/dist/commands/status.js +22 -4
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/train.d.ts +33 -0
- package/dist/commands/train.d.ts.map +1 -0
- package/dist/commands/train.js +510 -0
- package/dist/commands/train.js.map +1 -0
- package/dist/commands/verify.d.ts +14 -0
- package/dist/commands/verify.d.ts.map +1 -0
- package/dist/commands/verify.js +276 -0
- package/dist/commands/verify.js.map +1 -0
- package/dist/commands/viz.d.ts.map +1 -1
- package/dist/commands/viz.js +417 -0
- package/dist/commands/viz.js.map +1 -1
- package/dist/dashboard-static/assets/index-CW9ZxqX8.css +1 -0
- package/dist/dashboard-static/assets/index-DNN__p4K.js +121 -0
- package/dist/dashboard-static/index.html +2 -2
- package/dist/index.js +324 -64
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-config.d.ts +52 -0
- package/dist/lib/agent-config.d.ts.map +1 -0
- package/dist/lib/agent-config.js +231 -0
- package/dist/lib/agent-config.js.map +1 -0
- package/dist/lib/agent-generator.d.ts +10 -0
- package/dist/lib/agent-generator.d.ts.map +1 -1
- package/dist/lib/agent-generator.js +64 -10
- package/dist/lib/agent-generator.js.map +1 -1
- package/dist/lib/agent-session.d.ts +104 -0
- package/dist/lib/agent-session.d.ts.map +1 -0
- package/dist/lib/agent-session.js +635 -0
- package/dist/lib/agent-session.js.map +1 -0
- package/dist/lib/eval-snapshot.d.ts +47 -0
- package/dist/lib/eval-snapshot.d.ts.map +1 -0
- package/dist/lib/eval-snapshot.js +315 -0
- package/dist/lib/eval-snapshot.js.map +1 -0
- package/dist/lib/eval-store.d.ts +5 -0
- package/dist/lib/eval-store.d.ts.map +1 -1
- package/dist/lib/eval-store.js +33 -3
- package/dist/lib/eval-store.js.map +1 -1
- package/dist/lib/findings-engine.d.ts +51 -0
- package/dist/lib/findings-engine.d.ts.map +1 -0
- package/dist/lib/findings-engine.js +338 -0
- package/dist/lib/findings-engine.js.map +1 -0
- package/dist/lib/flow-engine.d.ts +8 -0
- package/dist/lib/flow-engine.d.ts.map +1 -1
- package/dist/lib/flow-engine.js +84 -2
- package/dist/lib/flow-engine.js.map +1 -1
- package/dist/lib/hub-client.d.ts +1 -0
- package/dist/lib/hub-client.d.ts.map +1 -1
- package/dist/lib/hub-client.js +33 -6
- package/dist/lib/hub-client.js.map +1 -1
- package/dist/lib/ide-panes.d.ts +58 -0
- package/dist/lib/ide-panes.d.ts.map +1 -0
- package/dist/lib/ide-panes.js +508 -0
- package/dist/lib/ide-panes.js.map +1 -0
- package/dist/lib/memory-db.js +4 -4
- package/dist/lib/memory-db.js.map +1 -1
- package/dist/lib/memory-indexer.d.ts.map +1 -1
- package/dist/lib/memory-indexer.js +3 -0
- package/dist/lib/memory-indexer.js.map +1 -1
- package/dist/lib/memory-search.d.ts +148 -4
- package/dist/lib/memory-search.d.ts.map +1 -1
- package/dist/lib/memory-search.js +496 -58
- package/dist/lib/memory-search.js.map +1 -1
- package/dist/lib/meta-orchestrator.d.ts +104 -0
- package/dist/lib/meta-orchestrator.d.ts.map +1 -0
- package/dist/lib/meta-orchestrator.js +373 -0
- package/dist/lib/meta-orchestrator.js.map +1 -0
- package/dist/lib/peer-agent-generator.d.ts.map +1 -1
- package/dist/lib/peer-agent-generator.js +43 -19
- package/dist/lib/peer-agent-generator.js.map +1 -1
- package/dist/lib/pi-sky/bridge.d.ts +55 -0
- package/dist/lib/pi-sky/bridge.d.ts.map +1 -0
- package/dist/lib/pi-sky/bridge.js +264 -0
- package/dist/lib/pi-sky/bridge.js.map +1 -0
- package/dist/lib/pi-sky/cost-monitor.d.ts +21 -0
- package/dist/lib/pi-sky/cost-monitor.d.ts.map +1 -0
- package/dist/lib/pi-sky/cost-monitor.js +126 -0
- package/dist/lib/pi-sky/cost-monitor.js.map +1 -0
- package/dist/lib/pi-sky/eval-sweep.d.ts +27 -0
- package/dist/lib/pi-sky/eval-sweep.d.ts.map +1 -0
- package/dist/lib/pi-sky/eval-sweep.js +141 -0
- package/dist/lib/pi-sky/eval-sweep.js.map +1 -0
- package/dist/lib/pi-sky/event-router.d.ts +32 -0
- package/dist/lib/pi-sky/event-router.d.ts.map +1 -0
- package/dist/lib/pi-sky/event-router.js +176 -0
- package/dist/lib/pi-sky/event-router.js.map +1 -0
- package/dist/lib/pi-sky/experiment.d.ts +9 -0
- package/dist/lib/pi-sky/experiment.d.ts.map +1 -0
- package/dist/lib/pi-sky/experiment.js +83 -0
- package/dist/lib/pi-sky/experiment.js.map +1 -0
- package/dist/lib/pi-sky/index.d.ts +16 -0
- package/dist/lib/pi-sky/index.d.ts.map +1 -0
- package/dist/lib/pi-sky/index.js +16 -0
- package/dist/lib/pi-sky/index.js.map +1 -0
- package/dist/lib/pi-sky/stratus-gate.d.ts +28 -0
- package/dist/lib/pi-sky/stratus-gate.d.ts.map +1 -0
- package/dist/lib/pi-sky/stratus-gate.js +61 -0
- package/dist/lib/pi-sky/stratus-gate.js.map +1 -0
- package/dist/lib/pi-sky/swarm.d.ts +28 -0
- package/dist/lib/pi-sky/swarm.d.ts.map +1 -0
- package/dist/lib/pi-sky/swarm.js +208 -0
- package/dist/lib/pi-sky/swarm.js.map +1 -0
- package/dist/lib/pi-sky/types.d.ts +139 -0
- package/dist/lib/pi-sky/types.d.ts.map +1 -0
- package/dist/lib/pi-sky/types.js +2 -0
- package/dist/lib/pi-sky/types.js.map +1 -0
- package/dist/lib/pi-sky/voice-bridge.d.ts +20 -0
- package/dist/lib/pi-sky/voice-bridge.d.ts.map +1 -0
- package/dist/lib/pi-sky/voice-bridge.js +91 -0
- package/dist/lib/pi-sky/voice-bridge.js.map +1 -0
- package/dist/lib/policy-head.d.ts +40 -0
- package/dist/lib/policy-head.d.ts.map +1 -0
- package/dist/lib/policy-head.js +234 -0
- package/dist/lib/policy-head.js.map +1 -0
- package/dist/lib/predictor.d.ts +10 -0
- package/dist/lib/predictor.d.ts.map +1 -1
- package/dist/lib/predictor.js +46 -7
- package/dist/lib/predictor.js.map +1 -1
- package/dist/lib/replay-buffer.d.ts +93 -0
- package/dist/lib/replay-buffer.d.ts.map +1 -0
- package/dist/lib/replay-buffer.js +302 -0
- package/dist/lib/replay-buffer.js.map +1 -0
- package/dist/lib/sentinel-rl.d.ts +97 -0
- package/dist/lib/sentinel-rl.d.ts.map +1 -0
- package/dist/lib/sentinel-rl.js +430 -0
- package/dist/lib/sentinel-rl.js.map +1 -0
- package/dist/lib/session-lock.d.ts +61 -0
- package/dist/lib/session-lock.d.ts.map +1 -0
- package/dist/lib/session-lock.js +438 -0
- package/dist/lib/session-lock.js.map +1 -0
- package/dist/lib/setup/agent-generator.d.ts +18 -0
- package/dist/lib/setup/agent-generator.d.ts.map +1 -0
- package/dist/lib/setup/agent-generator.js +114 -0
- package/dist/lib/setup/agent-generator.js.map +1 -0
- package/dist/lib/setup/context-analyzer.d.ts +16 -0
- package/dist/lib/setup/context-analyzer.d.ts.map +1 -0
- package/dist/lib/setup/context-analyzer.js +112 -0
- package/dist/lib/setup/context-analyzer.js.map +1 -0
- package/dist/lib/setup/doc-auditor.d.ts +54 -0
- package/dist/lib/setup/doc-auditor.d.ts.map +1 -0
- package/dist/lib/setup/doc-auditor.js +629 -0
- package/dist/lib/setup/doc-auditor.js.map +1 -0
- package/dist/lib/setup/domain-generator.d.ts +7 -0
- package/dist/lib/setup/domain-generator.d.ts.map +1 -0
- package/dist/lib/setup/domain-generator.js +58 -0
- package/dist/lib/setup/domain-generator.js.map +1 -0
- package/dist/lib/setup/smart-eval-generator.d.ts +38 -0
- package/dist/lib/setup/smart-eval-generator.d.ts.map +1 -0
- package/dist/lib/setup/smart-eval-generator.js +378 -0
- package/dist/lib/setup/smart-eval-generator.js.map +1 -0
- package/dist/lib/setup/smart-recommender.d.ts +63 -0
- package/dist/lib/setup/smart-recommender.d.ts.map +1 -0
- package/dist/lib/setup/smart-recommender.js +329 -0
- package/dist/lib/setup/smart-recommender.js.map +1 -0
- package/dist/lib/setup/spec-generator.d.ts +63 -0
- package/dist/lib/setup/spec-generator.d.ts.map +1 -0
- package/dist/lib/setup/spec-generator.js +310 -0
- package/dist/lib/setup/spec-generator.js.map +1 -0
- package/dist/lib/setup/violation-agent-generator.d.ts +32 -0
- package/dist/lib/setup/violation-agent-generator.d.ts.map +1 -0
- package/dist/lib/setup/violation-agent-generator.js +255 -0
- package/dist/lib/setup/violation-agent-generator.js.map +1 -0
- package/dist/lib/stratus-client.d.ts +1 -0
- package/dist/lib/stratus-client.d.ts.map +1 -1
- package/dist/lib/stratus-client.js +24 -2
- package/dist/lib/stratus-client.js.map +1 -1
- package/dist/lib/telemetry-agent-v2.d.ts +128 -0
- package/dist/lib/telemetry-agent-v2.d.ts.map +1 -0
- package/dist/lib/telemetry-agent-v2.js +1042 -0
- package/dist/lib/telemetry-agent-v2.js.map +1 -0
- package/dist/lib/telemetry-agent.d.ts.map +1 -1
- package/dist/lib/telemetry-agent.js +27 -6
- package/dist/lib/telemetry-agent.js.map +1 -1
- package/dist/lib/telemetry-digest.d.ts.map +1 -1
- package/dist/lib/telemetry-digest.js +27 -5
- package/dist/lib/telemetry-digest.js.map +1 -1
- package/dist/lib/telemetry.d.ts.map +1 -1
- package/dist/lib/telemetry.js +29 -4
- package/dist/lib/telemetry.js.map +1 -1
- package/dist/lib/text-preprocessing.d.ts +83 -0
- package/dist/lib/text-preprocessing.d.ts.map +1 -0
- package/dist/lib/text-preprocessing.js +261 -0
- package/dist/lib/text-preprocessing.js.map +1 -0
- package/dist/lib/training-buffer.d.ts +86 -0
- package/dist/lib/training-buffer.d.ts.map +1 -0
- package/dist/lib/training-buffer.js +139 -0
- package/dist/lib/training-buffer.js.map +1 -0
- package/dist/lib/tuple-miner.d.ts +30 -0
- package/dist/lib/tuple-miner.d.ts.map +1 -0
- package/dist/lib/tuple-miner.js +427 -0
- package/dist/lib/tuple-miner.js.map +1 -0
- package/dist/lib/vm-backend.d.ts +72 -0
- package/dist/lib/vm-backend.d.ts.map +1 -0
- package/dist/lib/vm-backend.js +175 -0
- package/dist/lib/vm-backend.js.map +1 -0
- package/dist/lib/workspace/backend.d.ts +53 -0
- package/dist/lib/workspace/backend.d.ts.map +1 -0
- package/dist/lib/workspace/backend.js +37 -0
- package/dist/lib/workspace/backend.js.map +1 -0
- package/dist/lib/workspace/cmux-adapter.d.ts +46 -0
- package/dist/lib/workspace/cmux-adapter.d.ts.map +1 -0
- package/dist/lib/workspace/cmux-adapter.js +261 -0
- package/dist/lib/workspace/cmux-adapter.js.map +1 -0
- package/dist/lib/workspace/data-pipeline.d.ts +35 -0
- package/dist/lib/workspace/data-pipeline.d.ts.map +1 -0
- package/dist/lib/workspace/data-pipeline.js +463 -0
- package/dist/lib/workspace/data-pipeline.js.map +1 -0
- package/dist/lib/workspace/engine.d.ts +64 -0
- package/dist/lib/workspace/engine.d.ts.map +1 -0
- package/dist/lib/workspace/engine.js +397 -0
- package/dist/lib/workspace/engine.js.map +1 -0
- package/dist/lib/workspace/notifications.d.ts +14 -0
- package/dist/lib/workspace/notifications.d.ts.map +1 -0
- package/dist/lib/workspace/notifications.js +41 -0
- package/dist/lib/workspace/notifications.js.map +1 -0
- package/dist/lib/workspace/surface-registry.d.ts +49 -0
- package/dist/lib/workspace/surface-registry.d.ts.map +1 -0
- package/dist/lib/workspace/surface-registry.js +217 -0
- package/dist/lib/workspace/surface-registry.js.map +1 -0
- package/dist/lib/workspace/surface-type.d.ts +153 -0
- package/dist/lib/workspace/surface-type.d.ts.map +1 -0
- package/dist/lib/workspace/surface-type.js +9 -0
- package/dist/lib/workspace/surface-type.js.map +1 -0
- package/dist/lib/workspace/surfaces/agent-overview.d.ts +16 -0
- package/dist/lib/workspace/surfaces/agent-overview.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/agent-overview.js +116 -0
- package/dist/lib/workspace/surfaces/agent-overview.js.map +1 -0
- package/dist/lib/workspace/surfaces/agent.d.ts +16 -0
- package/dist/lib/workspace/surfaces/agent.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/agent.js +112 -0
- package/dist/lib/workspace/surfaces/agent.js.map +1 -0
- package/dist/lib/workspace/surfaces/claude.d.ts +15 -0
- package/dist/lib/workspace/surfaces/claude.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/claude.js +23 -0
- package/dist/lib/workspace/surfaces/claude.js.map +1 -0
- package/dist/lib/workspace/surfaces/dashboard.d.ts +21 -0
- package/dist/lib/workspace/surfaces/dashboard.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/dashboard.js +32 -0
- package/dist/lib/workspace/surfaces/dashboard.js.map +1 -0
- package/dist/lib/workspace/surfaces/eval.d.ts +15 -0
- package/dist/lib/workspace/surfaces/eval.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/eval.js +42 -0
- package/dist/lib/workspace/surfaces/eval.js.map +1 -0
- package/dist/lib/workspace/surfaces/event-stream.d.ts +16 -0
- package/dist/lib/workspace/surfaces/event-stream.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/event-stream.js +40 -0
- package/dist/lib/workspace/surfaces/event-stream.js.map +1 -0
- package/dist/lib/workspace/surfaces/flow.d.ts +16 -0
- package/dist/lib/workspace/surfaces/flow.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/flow.js +49 -0
- package/dist/lib/workspace/surfaces/flow.js.map +1 -0
- package/dist/lib/workspace/surfaces/index.d.ts +16 -0
- package/dist/lib/workspace/surfaces/index.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/index.js +16 -0
- package/dist/lib/workspace/surfaces/index.js.map +1 -0
- package/dist/lib/workspace/surfaces/portfolio.d.ts +16 -0
- package/dist/lib/workspace/surfaces/portfolio.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/portfolio.js +102 -0
- package/dist/lib/workspace/surfaces/portfolio.js.map +1 -0
- package/dist/lib/workspace/surfaces/service.d.ts +16 -0
- package/dist/lib/workspace/surfaces/service.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/service.js +45 -0
- package/dist/lib/workspace/surfaces/service.js.map +1 -0
- package/dist/lib/workspace/surfaces/shell.d.ts +15 -0
- package/dist/lib/workspace/surfaces/shell.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/shell.js +19 -0
- package/dist/lib/workspace/surfaces/shell.js.map +1 -0
- package/dist/lib/workspace/surfaces/telemetry.d.ts +16 -0
- package/dist/lib/workspace/surfaces/telemetry.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/telemetry.js +48 -0
- package/dist/lib/workspace/surfaces/telemetry.js.map +1 -0
- package/dist/lib/workspace/surfaces/topology.d.ts +15 -0
- package/dist/lib/workspace/surfaces/topology.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/topology.js +19 -0
- package/dist/lib/workspace/surfaces/topology.js.map +1 -0
- package/dist/lib/workspace/surfaces/training.d.ts +16 -0
- package/dist/lib/workspace/surfaces/training.d.ts.map +1 -0
- package/dist/lib/workspace/surfaces/training.js +22 -0
- package/dist/lib/workspace/surfaces/training.js.map +1 -0
- package/dist/lib/workspace/tmux-adapter.d.ts +27 -0
- package/dist/lib/workspace/tmux-adapter.d.ts.map +1 -0
- package/dist/lib/workspace/tmux-adapter.js +106 -0
- package/dist/lib/workspace/tmux-adapter.js.map +1 -0
- package/dist/mcp/context-hub-mcp.js +7 -24
- package/dist/mcp/context-hub-mcp.js.map +1 -1
- package/dist/types/flows.d.ts +2 -0
- package/dist/types/flows.d.ts.map +1 -1
- package/dist/types/ide.d.ts +49 -0
- package/dist/types/ide.d.ts.map +1 -0
- package/dist/types/ide.js +5 -0
- package/dist/types/ide.js.map +1 -0
- package/dist/types/platform-digest.d.ts +228 -0
- package/dist/types/platform-digest.d.ts.map +1 -0
- package/dist/types/platform-digest.js +5 -0
- package/dist/types/platform-digest.js.map +1 -0
- package/dist/types/telemetry-digest.d.ts +2 -0
- package/dist/types/telemetry-digest.d.ts.map +1 -1
- package/dist/utils/ensure-project.d.ts +1 -0
- package/dist/utils/ensure-project.d.ts.map +1 -1
- package/dist/utils/ensure-project.js +19 -7
- package/dist/utils/ensure-project.js.map +1 -1
- package/dist/utils/jfl-config.d.ts +1 -0
- package/dist/utils/jfl-config.d.ts.map +1 -1
- package/dist/utils/jfl-config.js +19 -1
- package/dist/utils/jfl-config.js.map +1 -1
- package/dist/utils/jfl-paths.d.ts +5 -0
- package/dist/utils/jfl-paths.d.ts.map +1 -1
- package/dist/utils/jfl-paths.js +25 -3
- package/dist/utils/jfl-paths.js.map +1 -1
- package/package.json +3 -2
- package/packages/pi/AGENTS.md +112 -0
- package/packages/pi/extensions/agent-grid.ts +191 -0
- package/packages/pi/extensions/agent-names.ts +178 -0
- package/packages/pi/extensions/autoresearch.ts +427 -0
- package/packages/pi/extensions/bookmarks.ts +85 -0
- package/packages/pi/extensions/context.ts +184 -0
- package/packages/pi/extensions/crm-tool.ts +61 -0
- package/packages/pi/extensions/eval-tool.ts +224 -0
- package/packages/pi/extensions/eval.ts +60 -0
- package/packages/pi/extensions/footer.ts +239 -0
- package/packages/pi/extensions/hub-resolver.ts +63 -0
- package/packages/pi/extensions/hud-tool.ts +145 -0
- package/packages/pi/extensions/index.ts +405 -0
- package/packages/pi/extensions/journal.ts +224 -0
- package/packages/pi/extensions/map-bridge.ts +178 -0
- package/packages/pi/extensions/memory-tool.ts +73 -0
- package/packages/pi/extensions/notifications.ts +73 -0
- package/packages/pi/extensions/peter-parker.ts +202 -0
- package/packages/pi/extensions/policy-head-tool.ts +276 -0
- package/packages/pi/extensions/portfolio-bridge.ts +90 -0
- package/packages/pi/extensions/session.ts +142 -0
- package/packages/pi/extensions/shortcuts.ts +259 -0
- package/packages/pi/extensions/stratus-bridge.ts +115 -0
- package/packages/pi/extensions/synopsis-tool.ts +83 -0
- package/packages/pi/extensions/tool-renderers.ts +353 -0
- package/packages/pi/extensions/training-buffer-tool.ts +368 -0
- package/packages/pi/extensions/types.ts +163 -0
- package/packages/pi/package-lock.json +346 -0
- package/packages/pi/package.json +44 -0
- package/packages/pi/skills/agent-browser/SKILL.md +116 -0
- package/packages/pi/skills/brand-architect/SKILL.md +240 -0
- package/packages/pi/skills/brand-architect/config.yaml +137 -0
- package/packages/pi/skills/campaign-hud/config.yaml +112 -0
- package/packages/pi/skills/content-creator/SKILL.md +294 -0
- package/packages/pi/skills/context/SKILL.md +65 -0
- package/packages/pi/skills/debug/MULTI_AGENT.md +360 -0
- package/packages/pi/skills/debug/SKILL.md +554 -0
- package/packages/pi/skills/end/SKILL.md +1782 -0
- package/packages/pi/skills/eval/SKILL.md +75 -0
- package/packages/pi/skills/fly-deploy/SKILL.md +676 -0
- package/packages/pi/skills/founder-video/SKILL.md +467 -0
- package/packages/pi/skills/hud/SKILL.md +160 -0
- package/packages/pi/skills/orchestrate/SKILL.md +74 -0
- package/packages/pi/skills/pi-agents/SKILL.md +78 -0
- package/packages/pi/skills/react-best-practices/AGENTS.md +2249 -0
- package/packages/pi/skills/react-best-practices/README.md +123 -0
- package/packages/pi/skills/react-best-practices/SKILL.md +125 -0
- package/packages/pi/skills/react-best-practices/metadata.json +15 -0
- package/packages/pi/skills/react-best-practices/rules/_sections.md +46 -0
- package/packages/pi/skills/react-best-practices/rules/_template.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/packages/pi/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/packages/pi/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/packages/pi/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/packages/pi/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/packages/pi/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/packages/pi/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/packages/pi/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/packages/pi/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/packages/pi/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/packages/pi/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/packages/pi/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/packages/pi/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/packages/pi/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/packages/pi/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/packages/pi/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/packages/pi/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/packages/pi/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/packages/pi/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/packages/pi/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/packages/pi/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/packages/pi/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/packages/pi/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/packages/pi/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/packages/pi/skills/react-best-practices/rules/server-cache-react.md +26 -0
- package/packages/pi/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
- package/packages/pi/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/packages/pi/skills/remotion-best-practices/SKILL.md +43 -0
- package/packages/pi/skills/remotion-best-practices/rules/3d.md +86 -0
- package/packages/pi/skills/remotion-best-practices/rules/animations.md +29 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
- package/packages/pi/skills/remotion-best-practices/rules/assets.md +78 -0
- package/packages/pi/skills/remotion-best-practices/rules/audio.md +172 -0
- package/packages/pi/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
- package/packages/pi/skills/remotion-best-practices/rules/can-decode.md +75 -0
- package/packages/pi/skills/remotion-best-practices/rules/charts.md +58 -0
- package/packages/pi/skills/remotion-best-practices/rules/compositions.md +146 -0
- package/packages/pi/skills/remotion-best-practices/rules/display-captions.md +126 -0
- package/packages/pi/skills/remotion-best-practices/rules/extract-frames.md +229 -0
- package/packages/pi/skills/remotion-best-practices/rules/fonts.md +152 -0
- package/packages/pi/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
- package/packages/pi/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
- package/packages/pi/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
- package/packages/pi/skills/remotion-best-practices/rules/gifs.md +138 -0
- package/packages/pi/skills/remotion-best-practices/rules/images.md +130 -0
- package/packages/pi/skills/remotion-best-practices/rules/import-srt-captions.md +67 -0
- package/packages/pi/skills/remotion-best-practices/rules/lottie.md +68 -0
- package/packages/pi/skills/remotion-best-practices/rules/measuring-dom-nodes.md +35 -0
- package/packages/pi/skills/remotion-best-practices/rules/measuring-text.md +143 -0
- package/packages/pi/skills/remotion-best-practices/rules/sequencing.md +106 -0
- package/packages/pi/skills/remotion-best-practices/rules/tailwind.md +11 -0
- package/packages/pi/skills/remotion-best-practices/rules/text-animations.md +20 -0
- package/packages/pi/skills/remotion-best-practices/rules/timing.md +179 -0
- package/packages/pi/skills/remotion-best-practices/rules/transcribe-captions.md +19 -0
- package/packages/pi/skills/remotion-best-practices/rules/transitions.md +122 -0
- package/packages/pi/skills/remotion-best-practices/rules/trimming.md +53 -0
- package/packages/pi/skills/remotion-best-practices/rules/videos.md +171 -0
- package/packages/pi/skills/search/SKILL.md +220 -0
- package/packages/pi/skills/spec/SKILL.md +377 -0
- package/packages/pi/skills/startup/SKILL.md +315 -0
- package/packages/pi/skills/web-architect/SKILL.md +309 -0
- package/packages/pi/skills/x-algorithm/SKILL.md +305 -0
- package/packages/pi/teams/dev-team.yaml +63 -0
- package/packages/pi/teams/gtm-team.yaml +79 -0
- package/packages/pi/themes/jfl.theme.json +76 -0
- package/packages/pi/tsconfig.json +21 -0
- package/scripts/collect-tuples.sh +124 -0
- package/scripts/destroy-fleet.sh +37 -0
- package/scripts/jfl-ide.sh +48 -0
- package/scripts/session/session-cleanup.sh +4 -11
- package/scripts/session/session-init.sh +6 -0
- package/scripts/session/session-sync.sh +25 -0
- package/scripts/setup-branch-protection.sh +106 -0
- package/scripts/spawn-fleet.sh +144 -0
- package/scripts/train/requirements.txt +5 -0
- package/scripts/train/train-policy-head.py +477 -0
- package/scripts/train/v2/dataset.py +81 -0
- package/scripts/train/v2/domain.json +18 -0
- package/scripts/train/v2/eval.py +196 -0
- package/scripts/train/v2/generate_data.py +219 -0
- package/scripts/train/v2/infer.py +188 -0
- package/scripts/train/v2/model.py +112 -0
- package/scripts/train/v2/precompute.py +132 -0
- package/scripts/train/v2/train.py +302 -0
- package/scripts/train/v2/transform_buffer.py +227 -0
- package/scripts/train/v2/validate_data.py +115 -0
- package/scripts/train-policy-head.py +434 -0
- package/scripts/vm-swarm/README.md +301 -0
- package/scripts/vm-swarm/collect-tuples.sh +331 -0
- package/scripts/vm-swarm/create-base-template.sh +339 -0
- package/scripts/vm-swarm/kill-fleet.sh +204 -0
- package/scripts/vm-swarm/monitor-fleet.sh +346 -0
- package/scripts/vm-swarm/spawn-fleet.sh +304 -0
- package/template/.claude/settings.json +2 -15
- package/template/.github/workflows/jfl-eval.yml +6 -1
- package/template/.github/workflows/jfl-review.yml +4 -0
- package/template/scripts/session/session-cleanup.sh +2 -11
- package/template/scripts/session/session-end-hub.sh +72 -0
- package/template/scripts/session/session-end.sh +69 -6
- package/template/scripts/session/session-init.sh +55 -30
- package/template/scripts/session/session-lock.sh +464 -0
- package/template/scripts/session/session-start-hub.sh +105 -0
- package/template/templates/service-agent/workflows/jfl-eval.yml +19 -0
- package/dist/dashboard-static/assets/index-B6kRK9Rq.js +0 -116
- package/dist/dashboard-static/assets/index-BpdKJPLu.css +0 -1
package/dist/commands/peter.js
CHANGED
|
@@ -16,6 +16,9 @@ import { PeterParkerBridge } from "../lib/peter-parker-bridge.js";
|
|
|
16
16
|
import { getProjectHubUrl } from "../utils/context-hub-port.js";
|
|
17
17
|
import { TrajectoryLoader } from "../lib/trajectory-loader.js";
|
|
18
18
|
import { readEvals } from "../lib/eval-store.js";
|
|
19
|
+
import { TrainingBuffer } from "../lib/training-buffer.js";
|
|
20
|
+
import { PolicyHeadInference } from "../lib/policy-head.js";
|
|
21
|
+
import { PiRpcBridge, CostMonitor, EventRouter } from "../lib/pi-sky/index.js";
|
|
19
22
|
function hasRalphTui() {
|
|
20
23
|
try {
|
|
21
24
|
execSync("which ralph-tui", { stdio: "ignore" });
|
|
@@ -25,6 +28,15 @@ function hasRalphTui() {
|
|
|
25
28
|
return false;
|
|
26
29
|
}
|
|
27
30
|
}
|
|
31
|
+
function hasPi() {
|
|
32
|
+
try {
|
|
33
|
+
execSync("which pi", { stdio: "ignore" });
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
28
40
|
function getAuthToken(projectRoot) {
|
|
29
41
|
const tokenPath = path.join(projectRoot, ".jfl", "context-hub.token");
|
|
30
42
|
if (fs.existsSync(tokenPath)) {
|
|
@@ -192,6 +204,108 @@ async function postHubEvent(projectRoot, eventType, data) {
|
|
|
192
204
|
console.log(chalk.gray(" PP: Warning - could not post event to hub"));
|
|
193
205
|
}
|
|
194
206
|
}
|
|
207
|
+
async function initPiRuntime(projectRoot, options) {
|
|
208
|
+
const state = {
|
|
209
|
+
bridge: null,
|
|
210
|
+
costMonitor: null,
|
|
211
|
+
eventRouter: null,
|
|
212
|
+
};
|
|
213
|
+
// Check if Pi should be used
|
|
214
|
+
const shouldUsePi = options.usePi === true || (options.usePi !== false && hasPi());
|
|
215
|
+
if (!shouldUsePi) {
|
|
216
|
+
return state;
|
|
217
|
+
}
|
|
218
|
+
console.log(chalk.cyan(" Initializing Pi runtime..."));
|
|
219
|
+
// Create Pi RPC bridge
|
|
220
|
+
state.bridge = new PiRpcBridge({
|
|
221
|
+
cwd: projectRoot,
|
|
222
|
+
yolo: true,
|
|
223
|
+
noSession: true,
|
|
224
|
+
});
|
|
225
|
+
// Initialize cost monitor if budget is set
|
|
226
|
+
if (options.budget) {
|
|
227
|
+
const costConfig = {
|
|
228
|
+
maxCost: options.budget,
|
|
229
|
+
downgradeModel: { provider: "anthropic", modelId: "claude-haiku-4-5-20251001" },
|
|
230
|
+
downgradeThinkingLevel: "low",
|
|
231
|
+
upgradeModel: { provider: "anthropic", modelId: "claude-sonnet-4-20250514" },
|
|
232
|
+
upgradeThinkingLevel: "medium",
|
|
233
|
+
criticalKeywords: ["security", "auth", "payment", "migration", "deploy", "production"],
|
|
234
|
+
};
|
|
235
|
+
state.costMonitor = new CostMonitor(costConfig);
|
|
236
|
+
state.costMonitor.on("downgrade", (data) => {
|
|
237
|
+
console.log(chalk.yellow(` CostMonitor: Downgrading ${data.agent} to ${data.model} (budget: $${data.totalCost.toFixed(2)}/$${data.budget.toFixed(2)})`));
|
|
238
|
+
});
|
|
239
|
+
state.costMonitor.on("upgrade", (data) => {
|
|
240
|
+
console.log(chalk.cyan(` CostMonitor: Upgrading ${data.agent} to ${data.model} (critical path: ${data.reason})`));
|
|
241
|
+
});
|
|
242
|
+
state.costMonitor.on("cost_update", (data) => {
|
|
243
|
+
if (data.remaining < data.totalCost * 0.2) {
|
|
244
|
+
console.log(chalk.yellow(` CostMonitor: Budget low — $${data.remaining.toFixed(2)} remaining`));
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
// Initialize event router for Context Hub SSE
|
|
249
|
+
const hubUrl = getProjectHubUrl(projectRoot);
|
|
250
|
+
state.eventRouter = new EventRouter({
|
|
251
|
+
hubUrl,
|
|
252
|
+
routes: [
|
|
253
|
+
{
|
|
254
|
+
pattern: "eval:scored",
|
|
255
|
+
action: "steer",
|
|
256
|
+
messageTemplate: "SYSTEM EVENT: Eval regression detected. Agent={{data.agent}}, delta={{data.delta}}. Investigate what caused this before continuing.",
|
|
257
|
+
condition: (e) => Number(e.data?.delta ?? 0) < -0.01,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
pattern: "scope:impact",
|
|
261
|
+
action: "follow_up",
|
|
262
|
+
messageTemplate: "SYSTEM EVENT: Scope impact from {{data.agent}} on {{data.pattern}}. Consider if this affects your current work.",
|
|
263
|
+
},
|
|
264
|
+
],
|
|
265
|
+
});
|
|
266
|
+
state.eventRouter.on("route", (data) => {
|
|
267
|
+
console.log(chalk.gray(` EventRouter: ${data.event.type} → ${data.route.action}`));
|
|
268
|
+
});
|
|
269
|
+
state.eventRouter.on("error", (err) => {
|
|
270
|
+
// Silent — hub may not be running
|
|
271
|
+
});
|
|
272
|
+
return state;
|
|
273
|
+
}
|
|
274
|
+
async function runTaskWithPi(bridge, task, costMonitor, timeout = 300000) {
|
|
275
|
+
if (!bridge.started) {
|
|
276
|
+
await bridge.start();
|
|
277
|
+
}
|
|
278
|
+
// Check critical path for model upgrade if cost monitor is active
|
|
279
|
+
if (costMonitor) {
|
|
280
|
+
await costMonitor.checkCriticalPath("experiment", task);
|
|
281
|
+
}
|
|
282
|
+
// Create a promise that resolves when agent is done
|
|
283
|
+
const agentDone = new Promise((resolve) => {
|
|
284
|
+
bridge.once("agent_end", () => resolve());
|
|
285
|
+
});
|
|
286
|
+
// Send prompt
|
|
287
|
+
await bridge.prompt(task);
|
|
288
|
+
// Wait for completion with timeout
|
|
289
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
290
|
+
setTimeout(() => reject(new Error("Pi task timeout")), timeout);
|
|
291
|
+
});
|
|
292
|
+
try {
|
|
293
|
+
await Promise.race([agentDone, timeoutPromise]);
|
|
294
|
+
}
|
|
295
|
+
catch {
|
|
296
|
+
await bridge.abort().catch(() => { });
|
|
297
|
+
}
|
|
298
|
+
// Update cost tracking
|
|
299
|
+
if (costMonitor) {
|
|
300
|
+
await costMonitor.checkCost("experiment");
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
async function shutdownPiRuntime(state) {
|
|
304
|
+
state.eventRouter?.stop();
|
|
305
|
+
if (state.bridge && !state.bridge.exited) {
|
|
306
|
+
await state.bridge.shutdown().catch(() => { });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
195
309
|
async function runWithPR(projectRoot, task) {
|
|
196
310
|
if (!task) {
|
|
197
311
|
console.log(chalk.yellow("\n --task is required for pr mode"));
|
|
@@ -374,6 +488,51 @@ async function runWithPR(projectRoot, task) {
|
|
|
374
488
|
gitExec(["checkout", baseBranch], projectRoot);
|
|
375
489
|
console.log(chalk.green(" PP: Done\n"));
|
|
376
490
|
}
|
|
491
|
+
function buildRLState(evals, trajectoryLength, recentDeltas) {
|
|
492
|
+
const latest = evals.sort((a, b) => b.ts.localeCompare(a.ts))[0];
|
|
493
|
+
return {
|
|
494
|
+
composite_score: latest?.composite ?? 0,
|
|
495
|
+
dimension_scores: latest?.metrics ?? {},
|
|
496
|
+
tests_passing: latest?.metrics?.tests_passed ?? 0,
|
|
497
|
+
tests_total: latest?.metrics?.tests_total ?? 1,
|
|
498
|
+
trajectory_length: trajectoryLength,
|
|
499
|
+
recent_deltas: recentDeltas,
|
|
500
|
+
agent: "peter-parker",
|
|
501
|
+
};
|
|
502
|
+
}
|
|
503
|
+
function proposalToRLAction(p) {
|
|
504
|
+
return {
|
|
505
|
+
type: "experiment",
|
|
506
|
+
description: p.task,
|
|
507
|
+
files_affected: [],
|
|
508
|
+
scope: "medium",
|
|
509
|
+
branch: "",
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
async function rerankWithPolicyHead(projectRoot, proposals, evals, recentDeltas) {
|
|
513
|
+
const ph = new PolicyHeadInference(projectRoot);
|
|
514
|
+
if (!ph.isLoaded || proposals.length < 2)
|
|
515
|
+
return proposals;
|
|
516
|
+
const state = buildRLState(evals, 0, recentDeltas);
|
|
517
|
+
const actions = proposals.map(proposalToRLAction);
|
|
518
|
+
try {
|
|
519
|
+
const ranked = await ph.rankActions(state, actions);
|
|
520
|
+
const reordered = ranked.map(r => proposals[actions.indexOf(r.action)]);
|
|
521
|
+
const stats = ph.stats;
|
|
522
|
+
console.log(chalk.magenta(` Policy head re-ranked ${proposals.length} proposals (trained on ${stats.trained_on} tuples, rank_corr=${stats.rank_correlation.toFixed(3)})`));
|
|
523
|
+
for (let i = 0; i < ranked.length; i++) {
|
|
524
|
+
const r = ranked[i];
|
|
525
|
+
const p = reordered[i];
|
|
526
|
+
console.log(chalk.gray(` #${i + 1} [pred=${r.predictedReward.toFixed(4)}] ${p.task.slice(0, 60)}`));
|
|
527
|
+
}
|
|
528
|
+
console.log();
|
|
529
|
+
return reordered;
|
|
530
|
+
}
|
|
531
|
+
catch (err) {
|
|
532
|
+
console.log(chalk.yellow(` Policy head ranking failed: ${err.message}`));
|
|
533
|
+
return proposals;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
377
536
|
function writeJournalEntry(projectRoot, entry) {
|
|
378
537
|
const journalDir = path.join(projectRoot, ".jfl", "journal");
|
|
379
538
|
if (!fs.existsSync(journalDir)) {
|
|
@@ -484,9 +643,14 @@ Respond with ONLY a JSON array, no other text.`;
|
|
|
484
643
|
const content = response.choices[0]?.message?.content || "";
|
|
485
644
|
const jsonMatch = content.match(/\[[\s\S]*\]/);
|
|
486
645
|
if (jsonMatch) {
|
|
487
|
-
|
|
646
|
+
let proposals = JSON.parse(jsonMatch[0]);
|
|
488
647
|
if (proposals.length > 0) {
|
|
489
648
|
proposals.sort((a, b) => b.predicted_delta - a.predicted_delta);
|
|
649
|
+
const recentDeltas = experimentEntries
|
|
650
|
+
.slice(0, 5)
|
|
651
|
+
.map(e => e.score_delta ?? 0)
|
|
652
|
+
.filter((d) => typeof d === "number");
|
|
653
|
+
proposals = await rerankWithPolicyHead(projectRoot, proposals, evals, recentDeltas);
|
|
490
654
|
console.log(chalk.bold(" Top 3 Proposals:\n"));
|
|
491
655
|
for (let i = 0; i < Math.min(3, proposals.length); i++) {
|
|
492
656
|
const p = proposals[i];
|
|
@@ -560,20 +724,52 @@ Respond with ONLY a JSON array, no other text.`;
|
|
|
560
724
|
console.log(chalk.cyan(" Dispatching to Peter Parker PR workflow...\n"));
|
|
561
725
|
await runWithPR(projectRoot, proposal.task);
|
|
562
726
|
}
|
|
563
|
-
async function runAutoresearch(projectRoot,
|
|
727
|
+
async function runAutoresearch(projectRoot, options) {
|
|
728
|
+
const { rounds, budget, usePi } = options;
|
|
564
729
|
console.log(chalk.bold(`\n Peter Parker - Autoresearch Mode (${rounds} rounds)\n`));
|
|
565
730
|
console.log(chalk.gray(" Pattern: branch → change → eval → keep|revert → repeat"));
|
|
566
|
-
console.log(chalk.gray(" Only the winning experiment gets a PR
|
|
567
|
-
if (
|
|
568
|
-
console.log(chalk.
|
|
731
|
+
console.log(chalk.gray(" Only the winning experiment gets a PR."));
|
|
732
|
+
if (budget) {
|
|
733
|
+
console.log(chalk.gray(` Budget: $${budget.toFixed(2)}`));
|
|
734
|
+
}
|
|
735
|
+
if (usePi || (usePi !== false && hasPi())) {
|
|
736
|
+
console.log(chalk.cyan(" Runtime: Pi (RPC)"));
|
|
737
|
+
}
|
|
738
|
+
else {
|
|
739
|
+
console.log(chalk.gray(" Runtime: claude CLI"));
|
|
740
|
+
}
|
|
741
|
+
console.log();
|
|
742
|
+
// Initialize Pi runtime if available
|
|
743
|
+
const piState = await initPiRuntime(projectRoot, { budget, usePi });
|
|
744
|
+
const usePiRuntime = piState.bridge !== null;
|
|
745
|
+
// Start event router to listen for eval regressions
|
|
746
|
+
if (piState.eventRouter && piState.bridge) {
|
|
747
|
+
piState.eventRouter.registerBridge("experiment", piState.bridge);
|
|
748
|
+
try {
|
|
749
|
+
await piState.eventRouter.startSse();
|
|
750
|
+
}
|
|
751
|
+
catch {
|
|
752
|
+
// Fall back to polling if SSE not available
|
|
753
|
+
await piState.eventRouter.startPolling(5000);
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
// Register bridge with cost monitor
|
|
757
|
+
if (piState.costMonitor && piState.bridge) {
|
|
758
|
+
piState.costMonitor.registerBridge("experiment", piState.bridge);
|
|
759
|
+
}
|
|
760
|
+
// Only require ralph-tui if not using Pi
|
|
761
|
+
if (!usePiRuntime && !hasRalphTui()) {
|
|
762
|
+
console.log(chalk.yellow(" ralph-tui is not installed (and Pi not available)"));
|
|
569
763
|
console.log(chalk.gray(" Install: bun install -g ralph-tui\n"));
|
|
570
764
|
return;
|
|
571
765
|
}
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
766
|
+
if (!usePiRuntime) {
|
|
767
|
+
const configPath = path.join(projectRoot, ".ralph-tui", "config.toml");
|
|
768
|
+
if (!fs.existsSync(configPath)) {
|
|
769
|
+
console.log(chalk.yellow(" No Peter Parker config found"));
|
|
770
|
+
console.log(chalk.gray(" Run: jfl peter setup\n"));
|
|
771
|
+
return;
|
|
772
|
+
}
|
|
577
773
|
}
|
|
578
774
|
const loader = new TrajectoryLoader(projectRoot);
|
|
579
775
|
const evals = readEvals(projectRoot);
|
|
@@ -582,9 +778,11 @@ async function runAutoresearch(projectRoot, rounds) {
|
|
|
582
778
|
return;
|
|
583
779
|
}
|
|
584
780
|
const baseBranch = "main";
|
|
585
|
-
const
|
|
586
|
-
|
|
587
|
-
|
|
781
|
+
const latestEval = evals.sort((a, b) => b.ts.localeCompare(a.ts))[0];
|
|
782
|
+
const baselinePassRate = latestEval?.composite ?? 0;
|
|
783
|
+
const baselineTotal = latestEval?.metrics?.tests_total ?? 0;
|
|
784
|
+
const baselineScore = baselinePassRate + (baselineTotal > 0 ? baselineTotal * 0.001 : 0);
|
|
785
|
+
console.log(chalk.gray(` Baseline composite: ${baselineScore.toFixed(4)} (${baselineTotal} tests)`));
|
|
588
786
|
const results = [];
|
|
589
787
|
let bestResult = null;
|
|
590
788
|
for (let round = 1; round <= rounds; round++) {
|
|
@@ -611,8 +809,40 @@ async function runAutoresearch(projectRoot, rounds) {
|
|
|
611
809
|
metrics: { composite: r.score }, composite: r.score,
|
|
612
810
|
model_version: `round-${r.round}`,
|
|
613
811
|
}))), 15);
|
|
614
|
-
const
|
|
812
|
+
const policyHead = new PolicyHeadInference(projectRoot);
|
|
813
|
+
const useMultiProposal = policyHead.isLoaded;
|
|
814
|
+
// v2 policy head: get recommended action type before generating proposals
|
|
815
|
+
let actionGuidance = "";
|
|
816
|
+
if (policyHead.isLoaded && policyHead.version >= 2) {
|
|
817
|
+
try {
|
|
818
|
+
const rlState = buildRLState(evals, round, results.slice(-5).map(r => r.delta));
|
|
819
|
+
const selection = await policyHead.selectAction(rlState, "Improve codebase quality");
|
|
820
|
+
actionGuidance = `\nPolicy head recommends action type: "${selection.action}" (confidence: ${(selection.confidence * 100).toFixed(0)}%).`;
|
|
821
|
+
if (selection.alternatives.length > 0) {
|
|
822
|
+
actionGuidance += ` Alternatives: ${selection.alternatives.map(a => `${a.action}(${(a.confidence * 100).toFixed(0)}%)`).join(", ")}.`;
|
|
823
|
+
}
|
|
824
|
+
actionGuidance += `\nFavor proposals that align with the "${selection.action}" action type.`;
|
|
825
|
+
console.log(chalk.magenta(` Policy head v2 recommends: ${selection.action} (${(selection.confidence * 100).toFixed(0)}%)`));
|
|
826
|
+
}
|
|
827
|
+
catch {
|
|
828
|
+
// v2 not available, continue without guidance
|
|
829
|
+
}
|
|
830
|
+
}
|
|
831
|
+
const prompt = useMultiProposal
|
|
832
|
+
? `Autoresearch round ${round}/${rounds}. Suggest 3 specific improvements ranked by expected impact.
|
|
833
|
+
${actionGuidance}
|
|
834
|
+
Eval history:
|
|
835
|
+
${evalSummary}
|
|
836
|
+
|
|
837
|
+
Already tried (avoid these):
|
|
838
|
+
${pastTitles.map(t => `- ${t}`).join("\n") || "Nothing yet"}
|
|
615
839
|
|
|
840
|
+
Previous rounds this session:
|
|
841
|
+
${results.map(r => `- Round ${r.round}: "${r.task}" → delta=${r.delta > 0 ? "+" : ""}${r.delta.toFixed(4)}`).join("\n") || "None yet"}
|
|
842
|
+
|
|
843
|
+
Respond with ONLY a JSON array of 3 objects: [{"task": "...", "predicted_delta": 0.0-1.0, "reasoning": "...", "risk": "..."}, ...]`
|
|
844
|
+
: `Autoresearch round ${round}/${rounds}. Suggest ONE specific improvement.
|
|
845
|
+
${actionGuidance}
|
|
616
846
|
Eval history:
|
|
617
847
|
${evalSummary}
|
|
618
848
|
|
|
@@ -626,13 +856,25 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
626
856
|
{"task": "...", "predicted_delta": 0.0-1.0, "reasoning": "...", "risk": "..."}`;
|
|
627
857
|
const response = await stratus.reason(prompt, {
|
|
628
858
|
temperature: 0.8 + (round * 0.05),
|
|
629
|
-
maxTokens: 500,
|
|
859
|
+
maxTokens: useMultiProposal ? 1500 : 500,
|
|
630
860
|
featureContext: "autoresearch",
|
|
631
861
|
});
|
|
632
862
|
const content = response.choices[0]?.message?.content || "";
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
863
|
+
if (useMultiProposal) {
|
|
864
|
+
const jsonMatch = content.match(/\[[\s\S]*\]/);
|
|
865
|
+
if (jsonMatch) {
|
|
866
|
+
let proposals = JSON.parse(jsonMatch[0]);
|
|
867
|
+
const recentDeltas = results.slice(-5).map(r => r.delta);
|
|
868
|
+
proposals = await rerankWithPolicyHead(projectRoot, proposals, evals, recentDeltas);
|
|
869
|
+
if (proposals.length > 0)
|
|
870
|
+
proposal = proposals[0];
|
|
871
|
+
}
|
|
872
|
+
}
|
|
873
|
+
if (!proposal) {
|
|
874
|
+
const jsonMatch = content.match(/\{[\s\S]*\}/);
|
|
875
|
+
if (jsonMatch) {
|
|
876
|
+
proposal = JSON.parse(jsonMatch[0]);
|
|
877
|
+
}
|
|
636
878
|
}
|
|
637
879
|
}
|
|
638
880
|
catch (err) {
|
|
@@ -677,40 +919,56 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
677
919
|
console.log(chalk.red(` Failed to create branch ${branchName}`));
|
|
678
920
|
continue;
|
|
679
921
|
}
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
const prdPath = path.join(ralphDir, "autoresearch-task.json");
|
|
685
|
-
const prd = {
|
|
686
|
-
name: "Autoresearch Task",
|
|
687
|
-
branchName: `ralph/autoresearch-${Date.now()}`,
|
|
688
|
-
description: proposal.task,
|
|
689
|
-
userStories: [{
|
|
690
|
-
id: "US-001",
|
|
691
|
-
title: proposal.task.slice(0, 80),
|
|
692
|
-
description: proposal.task,
|
|
693
|
-
acceptanceCriteria: ["Task completed"],
|
|
694
|
-
priority: 1, passes: false, notes: "", dependsOn: [],
|
|
695
|
-
}],
|
|
696
|
-
metadata: { updatedAt: new Date().toISOString() },
|
|
697
|
-
};
|
|
698
|
-
fs.writeFileSync(prdPath, JSON.stringify(prd, null, 2));
|
|
699
|
-
const env = { ...process.env };
|
|
700
|
-
delete env.CLAUDECODE;
|
|
701
|
-
delete env.CLAUDE_CODE;
|
|
702
|
-
const child = spawn("ralph-tui", ["run", "--listen", "--prd", prdPath, "--headless"], {
|
|
703
|
-
cwd: projectRoot, stdio: "inherit", env,
|
|
704
|
-
});
|
|
705
|
-
child.on("error", () => { try {
|
|
706
|
-
fs.unlinkSync(prdPath);
|
|
922
|
+
// Run the task using Pi runtime or claude CLI
|
|
923
|
+
if (usePiRuntime && piState.bridge) {
|
|
924
|
+
try {
|
|
925
|
+
await runTaskWithPi(piState.bridge, proposal.task, piState.costMonitor, 300000);
|
|
707
926
|
}
|
|
708
|
-
catch
|
|
709
|
-
|
|
710
|
-
fs.unlinkSync(prdPath);
|
|
927
|
+
catch (err) {
|
|
928
|
+
console.log(chalk.yellow(` Pi task failed: ${err.message}`));
|
|
711
929
|
}
|
|
712
|
-
|
|
713
|
-
|
|
930
|
+
}
|
|
931
|
+
else {
|
|
932
|
+
// Fall back to claude CLI
|
|
933
|
+
await new Promise((resolve) => {
|
|
934
|
+
const ralphDir = path.join(projectRoot, ".ralph-tui");
|
|
935
|
+
if (!fs.existsSync(ralphDir))
|
|
936
|
+
fs.mkdirSync(ralphDir, { recursive: true });
|
|
937
|
+
const prdPath = path.join(ralphDir, "autoresearch-task.json");
|
|
938
|
+
const prd = {
|
|
939
|
+
name: "Autoresearch Task",
|
|
940
|
+
branchName: `ralph/autoresearch-${Date.now()}`,
|
|
941
|
+
description: proposal.task,
|
|
942
|
+
userStories: [{
|
|
943
|
+
id: "US-001",
|
|
944
|
+
title: proposal.task.slice(0, 80),
|
|
945
|
+
description: proposal.task,
|
|
946
|
+
acceptanceCriteria: ["Task completed"],
|
|
947
|
+
priority: 1, passes: false, notes: "", dependsOn: [],
|
|
948
|
+
}],
|
|
949
|
+
metadata: { updatedAt: new Date().toISOString() },
|
|
950
|
+
};
|
|
951
|
+
fs.writeFileSync(prdPath, JSON.stringify(prd, null, 2));
|
|
952
|
+
const env = { ...process.env };
|
|
953
|
+
delete env.CLAUDECODE;
|
|
954
|
+
delete env.CLAUDE_CODE;
|
|
955
|
+
const child = spawn("claude", [
|
|
956
|
+
"--dangerously-skip-permissions",
|
|
957
|
+
"-p", proposal.task,
|
|
958
|
+
"--output-format", "text",
|
|
959
|
+
], {
|
|
960
|
+
cwd: projectRoot, stdio: "inherit", env,
|
|
961
|
+
});
|
|
962
|
+
child.on("error", () => { try {
|
|
963
|
+
fs.unlinkSync(prdPath);
|
|
964
|
+
}
|
|
965
|
+
catch { } resolve(); });
|
|
966
|
+
child.on("exit", () => { try {
|
|
967
|
+
fs.unlinkSync(prdPath);
|
|
968
|
+
}
|
|
969
|
+
catch { } resolve(); });
|
|
970
|
+
});
|
|
971
|
+
}
|
|
714
972
|
const diffCheck = gitExec(["diff", "--quiet", "HEAD"], projectRoot);
|
|
715
973
|
const untrackedResult = spawnSync("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
716
974
|
cwd: projectRoot, encoding: "utf-8", stdio: "pipe",
|
|
@@ -735,7 +993,9 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
735
993
|
total = json.numTotalTests || 1;
|
|
736
994
|
}
|
|
737
995
|
catch { }
|
|
738
|
-
const
|
|
996
|
+
const passRate = total > 0 ? passing / total : 0;
|
|
997
|
+
const testsAdded = total - baselineTotal;
|
|
998
|
+
const score = passRate + (testsAdded > 0 ? testsAdded * 0.001 : 0);
|
|
739
999
|
const delta = score - baselineScore;
|
|
740
1000
|
const result = {
|
|
741
1001
|
round,
|
|
@@ -749,8 +1009,8 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
749
1009
|
results.push(result);
|
|
750
1010
|
const emoji = delta > 0 ? "+" : delta < 0 ? "" : "=";
|
|
751
1011
|
console.log(chalk.bold(` Round ${round} result: ${score.toFixed(4)} (${emoji}${delta.toFixed(4)})`));
|
|
752
|
-
console.log(chalk.gray(` Tests: ${passing}/${total}`));
|
|
753
|
-
if (!bestResult || result.
|
|
1012
|
+
console.log(chalk.gray(` Tests: ${passing}/${total}${testsAdded > 0 ? chalk.green(` (+${testsAdded} new)`) : ""}`));
|
|
1013
|
+
if (!bestResult || result.delta > bestResult.delta) {
|
|
754
1014
|
bestResult = result;
|
|
755
1015
|
console.log(chalk.green(` New best! (round ${round})`));
|
|
756
1016
|
}
|
|
@@ -759,7 +1019,7 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
759
1019
|
ts: new Date().toISOString(),
|
|
760
1020
|
session: "autoresearch",
|
|
761
1021
|
type: "experiment",
|
|
762
|
-
status: delta > 0 ? "complete" : "incomplete",
|
|
1022
|
+
status: (delta > 0 || testsAdded > 0) ? "complete" : "incomplete",
|
|
763
1023
|
title: `Autoresearch R${round}: ${proposal.task.slice(0, 60)}`,
|
|
764
1024
|
summary: `Score: ${score.toFixed(4)}, delta: ${delta > 0 ? "+" : ""}${delta.toFixed(4)}`,
|
|
765
1025
|
detail: `Task: ${proposal.task}\nResult: ${passing}/${total} tests passing`,
|
|
@@ -768,6 +1028,39 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
768
1028
|
score_delta: delta,
|
|
769
1029
|
agent_id: "peter-parker",
|
|
770
1030
|
});
|
|
1031
|
+
const tb = new TrainingBuffer(projectRoot);
|
|
1032
|
+
tb.append({
|
|
1033
|
+
agent: "peter-parker",
|
|
1034
|
+
state: {
|
|
1035
|
+
composite_score: baselineScore,
|
|
1036
|
+
dimension_scores: evals.sort((a, b) => b.ts.localeCompare(a.ts))[0]?.metrics ?? {},
|
|
1037
|
+
tests_passing: evals.sort((a, b) => b.ts.localeCompare(a.ts))[0]?.metrics?.tests_passed ?? 0,
|
|
1038
|
+
tests_total: evals.sort((a, b) => b.ts.localeCompare(a.ts))[0]?.metrics?.tests_total ?? 1,
|
|
1039
|
+
trajectory_length: results.length,
|
|
1040
|
+
recent_deltas: results.slice(-5).map(r => r.delta),
|
|
1041
|
+
agent: "peter-parker",
|
|
1042
|
+
},
|
|
1043
|
+
action: {
|
|
1044
|
+
type: "experiment",
|
|
1045
|
+
description: proposal.task,
|
|
1046
|
+
files_affected: [],
|
|
1047
|
+
scope: "medium",
|
|
1048
|
+
branch: branchName,
|
|
1049
|
+
},
|
|
1050
|
+
reward: {
|
|
1051
|
+
composite_delta: delta,
|
|
1052
|
+
dimension_deltas: {},
|
|
1053
|
+
tests_added: testsAdded,
|
|
1054
|
+
quality_score: passRate,
|
|
1055
|
+
improved: delta > 0 || testsAdded > 0,
|
|
1056
|
+
prediction_error: Math.abs(proposal.predicted_delta - delta),
|
|
1057
|
+
},
|
|
1058
|
+
metadata: {
|
|
1059
|
+
branch: branchName,
|
|
1060
|
+
autoresearch_round: round,
|
|
1061
|
+
source: "autoresearch",
|
|
1062
|
+
},
|
|
1063
|
+
});
|
|
771
1064
|
gitExec(["checkout", baseBranch], projectRoot);
|
|
772
1065
|
}
|
|
773
1066
|
console.log(chalk.bold(`\n ── Autoresearch Complete ${"─".repeat(35)}\n`));
|
|
@@ -841,10 +1134,780 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
841
1134
|
}
|
|
842
1135
|
}
|
|
843
1136
|
gitExec(["stash", "pop"], projectRoot);
|
|
1137
|
+
// Shutdown Pi runtime
|
|
1138
|
+
if (piState.bridge || piState.eventRouter) {
|
|
1139
|
+
console.log(chalk.gray(" Shutting down Pi runtime..."));
|
|
1140
|
+
await shutdownPiRuntime(piState);
|
|
1141
|
+
if (piState.costMonitor) {
|
|
1142
|
+
console.log(chalk.gray(` Total cost: $${piState.costMonitor.totalCost.toFixed(4)}`));
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
844
1145
|
console.log();
|
|
845
1146
|
}
|
|
1147
|
+
// ============================================================================
|
|
1148
|
+
// Scoped Agent Commands
|
|
1149
|
+
// ============================================================================
|
|
1150
|
+
async function agentCreate(projectRoot) {
|
|
1151
|
+
const { writeAgentConfig, generateAgentToml } = await import("../lib/agent-config.js");
|
|
1152
|
+
const readline = await import("readline");
|
|
1153
|
+
const rl = readline.createInterface({
|
|
1154
|
+
input: process.stdin,
|
|
1155
|
+
output: process.stdout,
|
|
1156
|
+
});
|
|
1157
|
+
const ask = (q) => new Promise(resolve => rl.question(q, resolve));
|
|
1158
|
+
console.log(chalk.bold("\n Create Scoped Agent\n"));
|
|
1159
|
+
const name = await ask(" Agent name (e.g., search-quality): ");
|
|
1160
|
+
const scope = await ask(" Scope (e.g., search, tests, quality): ");
|
|
1161
|
+
const metric = await ask(" Metric (e.g., ndcg@10, test_pass_rate): ");
|
|
1162
|
+
const direction = await ask(" Direction (maximize/minimize) [maximize]: ") || "maximize";
|
|
1163
|
+
const timeBudget = await ask(" Time budget seconds [300]: ") || "300";
|
|
1164
|
+
const evalScript = await ask(" Eval script path [eval/eval.ts]: ") || "eval/eval.ts";
|
|
1165
|
+
const evalData = await ask(" Eval data path [eval/fixtures/data.jsonl]: ") || "eval/fixtures/data.jsonl";
|
|
1166
|
+
const filesInScope = await ask(" Files in scope (glob, comma-sep) [src/**]: ") || "src/**";
|
|
1167
|
+
rl.close();
|
|
1168
|
+
const configPath = writeAgentConfig(projectRoot, {
|
|
1169
|
+
name,
|
|
1170
|
+
scope,
|
|
1171
|
+
metric,
|
|
1172
|
+
direction: direction,
|
|
1173
|
+
time_budget_seconds: parseInt(timeBudget, 10),
|
|
1174
|
+
eval: {
|
|
1175
|
+
script: evalScript,
|
|
1176
|
+
data: evalData,
|
|
1177
|
+
},
|
|
1178
|
+
constraints: {
|
|
1179
|
+
files_in_scope: filesInScope.split(",").map(s => s.trim()),
|
|
1180
|
+
files_readonly: ["eval/**"],
|
|
1181
|
+
max_file_changes: 10,
|
|
1182
|
+
},
|
|
1183
|
+
policy: {
|
|
1184
|
+
embedding_model: "stratus-x1ac-base-claude-sonnet-4-6",
|
|
1185
|
+
exploration_rate: 0.2,
|
|
1186
|
+
decay_per_round: 0.01,
|
|
1187
|
+
min_exploration: 0.05,
|
|
1188
|
+
},
|
|
1189
|
+
});
|
|
1190
|
+
console.log(chalk.green(`\n Agent config created: ${configPath}\n`));
|
|
1191
|
+
}
|
|
1192
|
+
async function agentList(projectRoot) {
|
|
1193
|
+
const { listAgentConfigs, loadAgentConfig } = await import("../lib/agent-config.js");
|
|
1194
|
+
const agents = listAgentConfigs(projectRoot);
|
|
1195
|
+
if (agents.length === 0) {
|
|
1196
|
+
console.log(chalk.yellow("\n No agents configured."));
|
|
1197
|
+
console.log(chalk.gray(" Run: jfl peter agent create\n"));
|
|
1198
|
+
return;
|
|
1199
|
+
}
|
|
1200
|
+
console.log(chalk.bold("\n Configured Agents\n"));
|
|
1201
|
+
for (const name of agents) {
|
|
1202
|
+
try {
|
|
1203
|
+
const config = loadAgentConfig(projectRoot, name);
|
|
1204
|
+
console.log(chalk.cyan(` ${name}`));
|
|
1205
|
+
console.log(chalk.gray(` Scope: ${config.scope}`));
|
|
1206
|
+
console.log(chalk.gray(` Metric: ${config.metric} (${config.direction})`));
|
|
1207
|
+
console.log(chalk.gray(` Time budget: ${config.time_budget_seconds}s`));
|
|
1208
|
+
console.log(chalk.gray(` Files: ${config.constraints.files_in_scope.join(", ")}`));
|
|
1209
|
+
console.log();
|
|
1210
|
+
}
|
|
1211
|
+
catch (err) {
|
|
1212
|
+
console.log(chalk.red(` ${name}: Error loading config - ${err.message}`));
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
async function agentRun(projectRoot, agentName, roundsOverride) {
|
|
1217
|
+
const { loadAgentConfig, validateAgentConfig } = await import("../lib/agent-config.js");
|
|
1218
|
+
const { startSession, runBaseline, runRound, endSession, saveSessionState, writeExperimentHistory } = await import("../lib/agent-session.js");
|
|
1219
|
+
const { ReplayBuffer } = await import("../lib/replay-buffer.js");
|
|
1220
|
+
const { StratusClient } = await import("../lib/stratus-client.js");
|
|
1221
|
+
// Load and validate config
|
|
1222
|
+
let config;
|
|
1223
|
+
try {
|
|
1224
|
+
config = loadAgentConfig(projectRoot, agentName);
|
|
1225
|
+
}
|
|
1226
|
+
catch (err) {
|
|
1227
|
+
console.log(chalk.red(`\n Agent not found: ${agentName}`));
|
|
1228
|
+
console.log(chalk.gray(" Run: jfl peter agent list\n"));
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
const validation = validateAgentConfig(config, projectRoot);
|
|
1232
|
+
if (!validation.valid) {
|
|
1233
|
+
console.log(chalk.red(`\n Invalid agent config:`));
|
|
1234
|
+
for (const err of validation.errors) {
|
|
1235
|
+
console.log(chalk.red(` - ${err}`));
|
|
1236
|
+
}
|
|
1237
|
+
console.log();
|
|
1238
|
+
return;
|
|
1239
|
+
}
|
|
1240
|
+
// Use config.rounds as default (Karpathy: ~50 experiments per session)
|
|
1241
|
+
// Allow override via CLI for debugging/testing
|
|
1242
|
+
const rounds = roundsOverride ?? config.rounds ?? 50;
|
|
1243
|
+
// Get scope_files for display
|
|
1244
|
+
const rawScopeFiles = config.constraints.scope_files || config.constraints.files_in_scope || [];
|
|
1245
|
+
const displayScopeFiles = Array.isArray(rawScopeFiles) ? rawScopeFiles : [String(rawScopeFiles)];
|
|
1246
|
+
const scopeFilesDisplay = displayScopeFiles.slice(0, 3).join(", ") + (displayScopeFiles.length > 3 ? "..." : "");
|
|
1247
|
+
console.log(chalk.bold(`\n Running Scoped Agent: ${agentName} (${rounds} rounds)\n`));
|
|
1248
|
+
console.log(chalk.gray(` Metric: ${config.metric} (${config.direction})`));
|
|
1249
|
+
console.log(chalk.gray(` Time budget: ${config.time_budget_seconds}s per round`));
|
|
1250
|
+
console.log(chalk.gray(` Focus files: ${scopeFilesDisplay}`));
|
|
1251
|
+
console.log(chalk.gray(` Pattern: branch → change → eval → keep|revert → repeat\n`));
|
|
1252
|
+
// Start session
|
|
1253
|
+
const session = startSession(config, projectRoot);
|
|
1254
|
+
saveSessionState(session);
|
|
1255
|
+
console.log(chalk.cyan(` Session: ${session.id}`));
|
|
1256
|
+
console.log(chalk.cyan(` Branch: ${session.branch}`));
|
|
1257
|
+
console.log(chalk.gray(` Eval snapshot: ${session.evalSnapshot.hash.slice(0, 8)}\n`));
|
|
1258
|
+
// Run baseline
|
|
1259
|
+
console.log(chalk.gray(" Running baseline eval..."));
|
|
1260
|
+
let baseline;
|
|
1261
|
+
try {
|
|
1262
|
+
baseline = await runBaseline(session);
|
|
1263
|
+
}
|
|
1264
|
+
catch (err) {
|
|
1265
|
+
console.log(chalk.red(` Baseline eval failed: ${err.message}`));
|
|
1266
|
+
return;
|
|
1267
|
+
}
|
|
1268
|
+
console.log(chalk.green(` Baseline: ${baseline.toFixed(4)}\n`));
|
|
1269
|
+
const replayBuffer = new ReplayBuffer(projectRoot);
|
|
1270
|
+
const transitions = [];
|
|
1271
|
+
// Stratus for task generation
|
|
1272
|
+
const stratus = process.env.STRATUS_API_KEY
|
|
1273
|
+
? new StratusClient({ apiKey: process.env.STRATUS_API_KEY })
|
|
1274
|
+
: null;
|
|
1275
|
+
// Get scope_files from config (Karpathy pattern: focused file list)
|
|
1276
|
+
const rawScope = config.constraints.scope_files || config.constraints.files_in_scope || [];
|
|
1277
|
+
const scopeFiles = Array.isArray(rawScope) ? rawScope : [String(rawScope)];
|
|
1278
|
+
const scopeFilesStr = scopeFiles.slice(0, 5).join(", ");
|
|
1279
|
+
for (let round = 1; round <= rounds; round++) {
|
|
1280
|
+
console.log(chalk.bold(`\n ── Round ${round}/${rounds} ${"─".repeat(40)}\n`));
|
|
1281
|
+
// Generate task — informed by past experiment history
|
|
1282
|
+
// Default task uses scope_files for focused changes (Karpathy pattern)
|
|
1283
|
+
let task = `Improve ${config.metric} by modifying: ${scopeFilesStr}. Make ONE small, focused change.`;
|
|
1284
|
+
// Build history context from replay buffer + current session transitions
|
|
1285
|
+
const pastTuples = replayBuffer.getForAgent(config.name).slice(-20); // Last 20 tuples
|
|
1286
|
+
const keptExperiments = [];
|
|
1287
|
+
const rejectedExperiments = [];
|
|
1288
|
+
// From replay buffer (past sessions)
|
|
1289
|
+
for (const t of pastTuples) {
|
|
1290
|
+
const action = t.action?.description || "unknown";
|
|
1291
|
+
const reward = t.reward ?? 0;
|
|
1292
|
+
if (reward > 0) {
|
|
1293
|
+
keptExperiments.push(`"${action.slice(0, 50)}" (+${reward.toFixed(4)})`);
|
|
1294
|
+
}
|
|
1295
|
+
else {
|
|
1296
|
+
rejectedExperiments.push(`"${action.slice(0, 50)}"`);
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
// From current session transitions
|
|
1300
|
+
for (const t of transitions) {
|
|
1301
|
+
const action = t.action?.description || "unknown";
|
|
1302
|
+
const reward = t.reward ?? 0;
|
|
1303
|
+
if (reward > 0) {
|
|
1304
|
+
keptExperiments.push(`"${action.slice(0, 50)}" (+${reward.toFixed(4)})`);
|
|
1305
|
+
}
|
|
1306
|
+
else {
|
|
1307
|
+
rejectedExperiments.push(`"${action.slice(0, 50)}"`);
|
|
1308
|
+
}
|
|
1309
|
+
}
|
|
1310
|
+
let historyContext = "";
|
|
1311
|
+
if (keptExperiments.length > 0 || rejectedExperiments.length > 0) {
|
|
1312
|
+
historyContext = `
|
|
1313
|
+
|
|
1314
|
+
Experiment history for ${config.name}:
|
|
1315
|
+
KEPT (these worked — build on them): ${keptExperiments.slice(-5).join(", ") || "none yet"}
|
|
1316
|
+
REJECTED (do NOT repeat these): ${rejectedExperiments.slice(-5).join(", ") || "none yet"}
|
|
1317
|
+
|
|
1318
|
+
CRITICAL: Do NOT repeat rejected experiments. Try something NEW and DIFFERENT.`;
|
|
1319
|
+
}
|
|
1320
|
+
// Read product context (Layer 2) if available
|
|
1321
|
+
let productContext = "";
|
|
1322
|
+
const productContextPath = path.join(projectRoot, ".jfl", "product-context.md");
|
|
1323
|
+
if (fs.existsSync(productContextPath)) {
|
|
1324
|
+
const pc = fs.readFileSync(productContextPath, "utf-8");
|
|
1325
|
+
// Extract agent-specific guidance if present
|
|
1326
|
+
const agentSection = pc.match(new RegExp(`${config.name}[:\\s].*?(?=\\n[A-Z#]|$)`, "s"));
|
|
1327
|
+
productContext = agentSection
|
|
1328
|
+
? `\n\nProduct context for this agent:\n${agentSection[0].slice(0, 500)}`
|
|
1329
|
+
: `\n\nProduct context (summary):\n${pc.slice(0, 500)}`;
|
|
1330
|
+
}
|
|
1331
|
+
if (stratus) {
|
|
1332
|
+
try {
|
|
1333
|
+
// Enhanced prompt with scope_files and history
|
|
1334
|
+
const prompt = `Suggest ONE specific code change to improve the ${config.metric} metric (${config.direction}).
|
|
1335
|
+
|
|
1336
|
+
FOCUS FILES (modify only these): ${scopeFilesStr}
|
|
1337
|
+
CURRENT METRIC: ${session.baselineMetric.toFixed(4)}
|
|
1338
|
+
ROUND: ${round}/${rounds}
|
|
1339
|
+
${historyContext}${productContext}
|
|
1340
|
+
|
|
1341
|
+
Be concrete and actionable. Return just the task description (1-2 sentences).`;
|
|
1342
|
+
const response = await stratus.reason(prompt, { maxTokens: 200, temperature: 0.7 + round * 0.03 });
|
|
1343
|
+
task = response.choices[0]?.message?.content || task;
|
|
1344
|
+
}
|
|
1345
|
+
catch { }
|
|
1346
|
+
}
|
|
1347
|
+
const hypothesis = `Implementing this will improve ${config.metric}`;
|
|
1348
|
+
console.log(chalk.cyan(` Task: ${task.slice(0, 80)}...`));
|
|
1349
|
+
// Pass transitions to runRound so it can build experiment history (Karpathy pattern)
|
|
1350
|
+
const { result, transition } = await runRound(session, round, task, hypothesis, transitions);
|
|
1351
|
+
transitions.push(transition);
|
|
1352
|
+
// Write to replay buffer
|
|
1353
|
+
replayBuffer.write({
|
|
1354
|
+
agent: config.name,
|
|
1355
|
+
session_id: session.id,
|
|
1356
|
+
state_hash: transition.state_hash,
|
|
1357
|
+
state: transition.state,
|
|
1358
|
+
action_diff: transition.action_diff,
|
|
1359
|
+
action: transition.action,
|
|
1360
|
+
hypothesis,
|
|
1361
|
+
reward: result.delta,
|
|
1362
|
+
timestamp: new Date().toISOString(),
|
|
1363
|
+
});
|
|
1364
|
+
const emoji = result.kept ? chalk.green("✓") : chalk.red("✗");
|
|
1365
|
+
const deltaStr = result.delta > 0 ? `+${result.delta.toFixed(4)}` : result.delta.toFixed(4);
|
|
1366
|
+
console.log(` ${emoji} Result: ${result.metricAfter.toFixed(4)} (${deltaStr}) ${result.kept ? "KEPT" : "REVERTED"}`);
|
|
1367
|
+
}
|
|
1368
|
+
// End session
|
|
1369
|
+
const summary = await endSession(session, transitions);
|
|
1370
|
+
console.log(chalk.bold(`\n ── Session Complete ${"─".repeat(35)}\n`));
|
|
1371
|
+
console.log(chalk.gray(` Rounds: ${summary.rounds}`));
|
|
1372
|
+
console.log(chalk.gray(` Improved: ${summary.improvedRounds}`));
|
|
1373
|
+
console.log(chalk.gray(` Total delta: ${summary.totalDelta > 0 ? "+" : ""}${summary.totalDelta.toFixed(4)}`));
|
|
1374
|
+
console.log(chalk.gray(` Best delta: +${summary.bestDelta.toFixed(4)}`));
|
|
1375
|
+
if (summary.branchUrl) {
|
|
1376
|
+
console.log(chalk.green(`\n Branch pushed for review: ${summary.branchUrl}`));
|
|
1377
|
+
}
|
|
1378
|
+
if (summary.prUrl) {
|
|
1379
|
+
console.log(chalk.green(` PR: ${summary.prUrl}`));
|
|
1380
|
+
}
|
|
1381
|
+
console.log();
|
|
1382
|
+
}
|
|
1383
|
+
// ============================================================================
|
|
1384
|
+
// Telemetry Agent V2 Commands
|
|
1385
|
+
// ============================================================================
|
|
1386
|
+
async function runTelemetryAgent(projectRoot) {
|
|
1387
|
+
const { TelemetryAgentV2 } = await import("../lib/telemetry-agent-v2.js");
|
|
1388
|
+
console.log(chalk.bold("\n Telemetry Agent V2 - Platform Digest Analysis\n"));
|
|
1389
|
+
const agent = new TelemetryAgentV2({
|
|
1390
|
+
projectRoot,
|
|
1391
|
+
emitEvent: (type, data) => {
|
|
1392
|
+
console.log(chalk.gray(` [EVENT] ${type}`));
|
|
1393
|
+
},
|
|
1394
|
+
});
|
|
1395
|
+
console.log(chalk.gray(" Fetching platform digest..."));
|
|
1396
|
+
const result = await agent.run();
|
|
1397
|
+
if (!result.digest24h) {
|
|
1398
|
+
console.log(chalk.yellow("\n Could not fetch platform digest."));
|
|
1399
|
+
console.log(chalk.gray(" Check JFL_PLATFORM_URL and network connectivity.\n"));
|
|
1400
|
+
return;
|
|
1401
|
+
}
|
|
1402
|
+
console.log(chalk.green(`\n Digest fetched for ${result.digest24h.periodHours}h period\n`));
|
|
1403
|
+
// Show metrics
|
|
1404
|
+
if (result.metrics) {
|
|
1405
|
+
console.log(chalk.bold(" Current Metrics:"));
|
|
1406
|
+
console.log(chalk.gray(` Command Success Rate: ${(result.metrics.command_success_rate * 100).toFixed(1)}%`));
|
|
1407
|
+
console.log(chalk.gray(` Command P90 Latency: ${result.metrics.command_p90_latency_ms}ms`));
|
|
1408
|
+
console.log(chalk.gray(` Session Crash Rate: ${(result.metrics.session_crash_rate * 100).toFixed(2)}%`));
|
|
1409
|
+
console.log(chalk.gray(` Hub Crash Rate: ${(result.metrics.hub_crash_rate * 100).toFixed(2)}%`));
|
|
1410
|
+
console.log(chalk.gray(` Flow Completion Rate: ${(result.metrics.flow_completion_rate * 100).toFixed(1)}%`));
|
|
1411
|
+
console.log(chalk.gray(` Cost Per Session: $${result.metrics.cost_per_session_usd.toFixed(4)}`));
|
|
1412
|
+
console.log(chalk.gray(` Active Installs: ${result.metrics.active_installs}`));
|
|
1413
|
+
console.log(chalk.gray(` Error Clusters: ${result.metrics.error_cluster_count}`));
|
|
1414
|
+
console.log();
|
|
1415
|
+
}
|
|
1416
|
+
// Show alerts
|
|
1417
|
+
if (result.alerts.length > 0) {
|
|
1418
|
+
console.log(chalk.bold(chalk.red(" Alerts:")));
|
|
1419
|
+
for (const alert of result.alerts) {
|
|
1420
|
+
console.log(chalk.red(` ⚠ ${alert.name}: ${alert.percentChange.toFixed(1)}% decline`));
|
|
1421
|
+
console.log(chalk.gray(` ${alert.previous.toFixed(4)} → ${alert.current.toFixed(4)}`));
|
|
1422
|
+
}
|
|
1423
|
+
console.log();
|
|
1424
|
+
}
|
|
1425
|
+
// Show wins
|
|
1426
|
+
if (result.wins.length > 0) {
|
|
1427
|
+
console.log(chalk.bold(chalk.green(" Wins:")));
|
|
1428
|
+
for (const win of result.wins) {
|
|
1429
|
+
console.log(chalk.green(` ✓ ${win.name}: ${win.percentChange.toFixed(1)}% improvement`));
|
|
1430
|
+
console.log(chalk.gray(` ${win.previous.toFixed(4)} → ${win.current.toFixed(4)}`));
|
|
1431
|
+
}
|
|
1432
|
+
console.log();
|
|
1433
|
+
}
|
|
1434
|
+
// Show proposed agents
|
|
1435
|
+
if (result.proposedAgents.length > 0) {
|
|
1436
|
+
console.log(chalk.bold(" Proposed Agents:"));
|
|
1437
|
+
for (const agent of result.proposedAgents) {
|
|
1438
|
+
const priority = agent.priority === "high" ? chalk.red(agent.priority) :
|
|
1439
|
+
agent.priority === "medium" ? chalk.yellow(agent.priority) :
|
|
1440
|
+
chalk.gray(agent.priority);
|
|
1441
|
+
console.log(chalk.cyan(` ${agent.name} [${priority}]`));
|
|
1442
|
+
console.log(chalk.gray(` ${agent.reason}`));
|
|
1443
|
+
}
|
|
1444
|
+
console.log(chalk.gray(`\n Agent configs written to .jfl/agents/proposed/\n`));
|
|
1445
|
+
}
|
|
1446
|
+
// Show status
|
|
1447
|
+
const status = agent.getStatus();
|
|
1448
|
+
console.log(chalk.gray(` Run #${status.runCount}`));
|
|
1449
|
+
console.log(chalk.gray(` Training tuples generated: ${status.totalTrainingTuples}`));
|
|
1450
|
+
console.log();
|
|
1451
|
+
}
|
|
1452
|
+
async function runSentinelReview(projectRoot) {
|
|
1453
|
+
const { SentinelRL } = await import("../lib/sentinel-rl.js");
|
|
1454
|
+
console.log(chalk.bold("\n Sentinel - Nightly System Review\n"));
|
|
1455
|
+
const sentinel = new SentinelRL({
|
|
1456
|
+
projectRoot,
|
|
1457
|
+
emitEvent: (type, data) => {
|
|
1458
|
+
console.log(chalk.gray(` [EVENT] ${type}`));
|
|
1459
|
+
},
|
|
1460
|
+
});
|
|
1461
|
+
console.log(chalk.gray(" Collecting inputs..."));
|
|
1462
|
+
const { scores, recommendations, inputs } = await sentinel.run();
|
|
1463
|
+
// Show scores
|
|
1464
|
+
console.log(chalk.bold("\n System Scores:"));
|
|
1465
|
+
console.log(chalk.gray(` Product Health: ${(scores.productHealth * 100).toFixed(0)}% ${scoreEmoji(scores.productHealth)}`));
|
|
1466
|
+
console.log(chalk.gray(` Development Velocity: ${(scores.developmentVelocity * 100).toFixed(0)}% ${scoreEmoji(scores.developmentVelocity)}`));
|
|
1467
|
+
console.log(chalk.gray(` Agent Effectiveness: ${(scores.agentEffectiveness * 100).toFixed(0)}% ${scoreEmoji(scores.agentEffectiveness)}`));
|
|
1468
|
+
console.log(chalk.gray(` Data Quality: ${(scores.dataQuality * 100).toFixed(0)}% ${scoreEmoji(scores.dataQuality)}`));
|
|
1469
|
+
console.log(chalk.bold(` Composite: ${(scores.composite * 100).toFixed(0)}% ${scoreEmoji(scores.composite)}`));
|
|
1470
|
+
console.log();
|
|
1471
|
+
// Show recommendations
|
|
1472
|
+
if (recommendations.length > 0) {
|
|
1473
|
+
console.log(chalk.bold(" Recommendations:"));
|
|
1474
|
+
for (const rec of recommendations) {
|
|
1475
|
+
const priority = rec.priority === "high" ? chalk.red(`[${rec.priority}]`) :
|
|
1476
|
+
rec.priority === "medium" ? chalk.yellow(`[${rec.priority}]`) :
|
|
1477
|
+
chalk.gray(`[${rec.priority}]`);
|
|
1478
|
+
console.log(` ${priority} ${rec.description}`);
|
|
1479
|
+
console.log(chalk.gray(` ${rec.reason}`));
|
|
1480
|
+
}
|
|
1481
|
+
console.log();
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
console.log(chalk.green(" No recommendations at this time.\n"));
|
|
1485
|
+
}
|
|
1486
|
+
// Show data summary
|
|
1487
|
+
console.log(chalk.gray(` Journal entries analyzed: ${inputs.journalEntries.length}`));
|
|
1488
|
+
console.log(chalk.gray(` Eval entries analyzed: ${inputs.evalHistory.length}`));
|
|
1489
|
+
console.log(chalk.gray(` PR reviews analyzed: ${inputs.prReviews.length}`));
|
|
1490
|
+
console.log(chalk.gray(` Training tuples: ${inputs.trainingStats.total}`));
|
|
1491
|
+
console.log(chalk.gray(` Replay entries: ${inputs.replayStats.totalEntries}`));
|
|
1492
|
+
console.log(chalk.gray(`\n Report written to .jfl/SENTINEL-REPORT.md\n`));
|
|
1493
|
+
}
|
|
1494
|
+
function scoreEmoji(score) {
|
|
1495
|
+
if (score >= 0.8)
|
|
1496
|
+
return chalk.green("●");
|
|
1497
|
+
if (score >= 0.5)
|
|
1498
|
+
return chalk.yellow("●");
|
|
1499
|
+
return chalk.red("●");
|
|
1500
|
+
}
|
|
1501
|
+
async function showMetrics(projectRoot) {
|
|
1502
|
+
const { TelemetryAgentV2 } = await import("../lib/telemetry-agent-v2.js");
|
|
1503
|
+
console.log(chalk.bold("\n Current Platform Metrics\n"));
|
|
1504
|
+
const agent = new TelemetryAgentV2({ projectRoot });
|
|
1505
|
+
const metrics = await agent.getMetrics();
|
|
1506
|
+
if (!metrics) {
|
|
1507
|
+
console.log(chalk.yellow(" Could not fetch metrics from platform."));
|
|
1508
|
+
console.log(chalk.gray(" Check JFL_PLATFORM_URL and network connectivity.\n"));
|
|
1509
|
+
return;
|
|
1510
|
+
}
|
|
1511
|
+
const format = (value, isPercent = false) => {
|
|
1512
|
+
if (isPercent)
|
|
1513
|
+
return `${(value * 100).toFixed(1)}%`;
|
|
1514
|
+
return value.toFixed(4);
|
|
1515
|
+
};
|
|
1516
|
+
console.log(chalk.cyan(" Health Metrics:"));
|
|
1517
|
+
console.log(chalk.gray(` Command Success Rate: ${format(metrics.command_success_rate, true)}`));
|
|
1518
|
+
console.log(chalk.gray(` Session Crash Rate: ${format(metrics.session_crash_rate, true)}`));
|
|
1519
|
+
console.log(chalk.gray(` Hub Crash Rate: ${format(metrics.hub_crash_rate, true)}`));
|
|
1520
|
+
console.log(chalk.gray(` Flow Completion Rate: ${format(metrics.flow_completion_rate, true)}`));
|
|
1521
|
+
console.log();
|
|
1522
|
+
console.log(chalk.cyan(" Performance Metrics:"));
|
|
1523
|
+
console.log(chalk.gray(` Command P90 Latency: ${metrics.command_p90_latency_ms}ms`));
|
|
1524
|
+
console.log(chalk.gray(` MCP Avg Latency: ${metrics.mcp_avg_latency_ms.toFixed(1)}ms`));
|
|
1525
|
+
console.log();
|
|
1526
|
+
console.log(chalk.cyan(" Usage Metrics:"));
|
|
1527
|
+
console.log(chalk.gray(` Active Installs: ${metrics.active_installs}`));
|
|
1528
|
+
console.log(chalk.gray(` Error Clusters: ${metrics.error_cluster_count}`));
|
|
1529
|
+
console.log(chalk.gray(` Hook Hit Rate: ${format(metrics.hook_hit_rate, true)}`));
|
|
1530
|
+
console.log();
|
|
1531
|
+
console.log(chalk.cyan(" Cost Metrics:"));
|
|
1532
|
+
console.log(chalk.gray(` Cost Per Session: $${metrics.cost_per_session_usd.toFixed(4)}`));
|
|
1533
|
+
console.log();
|
|
1534
|
+
}
|
|
1535
|
+
async function runDailyLoop(projectRoot) {
|
|
1536
|
+
const { MetaOrchestrator } = await import("../lib/meta-orchestrator.js");
|
|
1537
|
+
const { loadAllAgentConfigs } = await import("../lib/agent-config.js");
|
|
1538
|
+
console.log(chalk.bold("\n Peter Parker - Daily RL Agent Loop\n"));
|
|
1539
|
+
const orchestrator = new MetaOrchestrator(projectRoot);
|
|
1540
|
+
const agents = orchestrator.getAgents();
|
|
1541
|
+
if (agents.length === 0) {
|
|
1542
|
+
console.log(chalk.yellow(" No RL agents configured."));
|
|
1543
|
+
console.log(chalk.gray(" Run: jfl onboard <service-path> to discover metrics"));
|
|
1544
|
+
console.log(chalk.gray(" Or: jfl peter agent create\n"));
|
|
1545
|
+
return;
|
|
1546
|
+
}
|
|
1547
|
+
console.log(chalk.gray(` Found ${agents.length} RL agent(s):\n`));
|
|
1548
|
+
for (const agent of agents) {
|
|
1549
|
+
console.log(chalk.gray(` • ${agent.name} (${agent.metric}, ${agent.direction})`));
|
|
1550
|
+
}
|
|
1551
|
+
console.log();
|
|
1552
|
+
// Read training buffer to check for stale agents
|
|
1553
|
+
const tb = new TrainingBuffer(projectRoot);
|
|
1554
|
+
const entries = tb.read();
|
|
1555
|
+
const now = Date.now();
|
|
1556
|
+
const staleThreshold = 24 * 60 * 60 * 1000; // 24 hours
|
|
1557
|
+
const staleAgents = [];
|
|
1558
|
+
const activeAgents = [];
|
|
1559
|
+
for (const agent of agents) {
|
|
1560
|
+
const agentEntries = entries.filter(e => e.agent === agent.name);
|
|
1561
|
+
const latestEntry = agentEntries.sort((a, b) => b.ts.localeCompare(a.ts))[0];
|
|
1562
|
+
if (!latestEntry) {
|
|
1563
|
+
staleAgents.push(agent.name);
|
|
1564
|
+
console.log(chalk.yellow(` ⚠ ${agent.name}: No training data (never run)`));
|
|
1565
|
+
}
|
|
1566
|
+
else {
|
|
1567
|
+
const lastRun = new Date(latestEntry.ts).getTime();
|
|
1568
|
+
if (now - lastRun > staleThreshold) {
|
|
1569
|
+
staleAgents.push(agent.name);
|
|
1570
|
+
const hoursAgo = Math.floor((now - lastRun) / (60 * 60 * 1000));
|
|
1571
|
+
console.log(chalk.yellow(` ⚠ ${agent.name}: Stale (${hoursAgo}h since last training)`));
|
|
1572
|
+
}
|
|
1573
|
+
else {
|
|
1574
|
+
activeAgents.push(agent.name);
|
|
1575
|
+
console.log(chalk.green(` ✓ ${agent.name}: Recent training data`));
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
console.log();
|
|
1580
|
+
// ── Pre-flight: Mine tuples + Synthesize product context ──
|
|
1581
|
+
console.log(chalk.cyan(" Pre-flight: Mining tuples from journals...\n"));
|
|
1582
|
+
try {
|
|
1583
|
+
const { mineAll } = await import("../lib/tuple-miner.js");
|
|
1584
|
+
const { tuples: minedTuples, stats: mineStats } = mineAll({ all: true });
|
|
1585
|
+
if (minedTuples.length > 0) {
|
|
1586
|
+
const existing = new Set(entries.map(e => e.id));
|
|
1587
|
+
let newCount = 0;
|
|
1588
|
+
for (const tuple of minedTuples) {
|
|
1589
|
+
const id = `tb_${Buffer.from(JSON.stringify(tuple.state) + JSON.stringify(tuple.action)).toString("base64").slice(0, 12)}`;
|
|
1590
|
+
if (!existing.has(id)) {
|
|
1591
|
+
tb.append({ ...tuple, id, v: "1", ts: new Date().toISOString() });
|
|
1592
|
+
newCount++;
|
|
1593
|
+
}
|
|
1594
|
+
}
|
|
1595
|
+
console.log(chalk.gray(` Mined ${mineStats.totalMined} tuples, ${newCount} new → buffer total: ${entries.length + newCount}`));
|
|
1596
|
+
}
|
|
1597
|
+
}
|
|
1598
|
+
catch (err) {
|
|
1599
|
+
console.log(chalk.yellow(` Tuple mining failed: ${err.message}`));
|
|
1600
|
+
}
|
|
1601
|
+
console.log(chalk.cyan("\n Pre-flight: Synthesizing product context...\n"));
|
|
1602
|
+
try {
|
|
1603
|
+
await runSynthesis(projectRoot);
|
|
1604
|
+
}
|
|
1605
|
+
catch (err) {
|
|
1606
|
+
console.log(chalk.yellow(` Synthesis failed: ${err.message}`));
|
|
1607
|
+
}
|
|
1608
|
+
// ── Layer 3: Strategic reasoning ──
|
|
1609
|
+
console.log(chalk.cyan("\n Layer 3: Strategic reasoning...\n"));
|
|
1610
|
+
try {
|
|
1611
|
+
const { StratusClient } = await import("../lib/stratus-client.js");
|
|
1612
|
+
const stratus = new StratusClient();
|
|
1613
|
+
const productContextPath = path.join(projectRoot, ".jfl", "product-context.md");
|
|
1614
|
+
const productCtx = fs.existsSync(productContextPath) ? fs.readFileSync(productContextPath, "utf-8").slice(0, 2000) : "No product context yet.";
|
|
1615
|
+
// Get recent results per agent
|
|
1616
|
+
const agentSummaries = agents.map(a => {
|
|
1617
|
+
const agentEntries = entries.filter(e => e.agent === a.name).slice(-5);
|
|
1618
|
+
const improved = agentEntries.filter(e => e.reward?.improved).length;
|
|
1619
|
+
return `${a.name} (${a.metric}, ${a.direction}): ${agentEntries.length} recent tuples, ${improved} improved`;
|
|
1620
|
+
}).join("\n");
|
|
1621
|
+
const strategicPrompt = `You are Peter Parker, a strategic agent orchestrator. Based on the product context and agent performance, decide:
|
|
1622
|
+
1. Which agents should run tonight (and why)
|
|
1623
|
+
2. Which agents to skip (and why)
|
|
1624
|
+
3. Any priority shifts or new metric suggestions
|
|
1625
|
+
|
|
1626
|
+
Product context:
|
|
1627
|
+
${productCtx}
|
|
1628
|
+
|
|
1629
|
+
Agent performance:
|
|
1630
|
+
${agentSummaries}
|
|
1631
|
+
|
|
1632
|
+
Stale agents (haven't run in 24h): ${staleAgents.join(", ") || "none"}
|
|
1633
|
+
|
|
1634
|
+
Be concise. Output a JSON object: { "run": ["agent1", "agent2"], "skip": ["agent3"], "reasoning": "brief explanation", "suggestions": "any new metrics or priority changes" }`;
|
|
1635
|
+
const response = await stratus.reason(strategicPrompt, { maxTokens: 500, temperature: 0.3 });
|
|
1636
|
+
const strategicText = response?.choices?.[0]?.message?.content || "";
|
|
1637
|
+
console.log(chalk.gray(` Strategic reasoning:\n ${strategicText.slice(0, 500)}`));
|
|
1638
|
+
// Try to parse JSON from response
|
|
1639
|
+
try {
|
|
1640
|
+
const jsonMatch = strategicText.match(/\{[\s\S]*\}/);
|
|
1641
|
+
if (jsonMatch) {
|
|
1642
|
+
const strategic = JSON.parse(jsonMatch[0]);
|
|
1643
|
+
if (strategic.reasoning) {
|
|
1644
|
+
console.log(chalk.cyan(`\n Reasoning: ${strategic.reasoning}`));
|
|
1645
|
+
}
|
|
1646
|
+
if (strategic.suggestions) {
|
|
1647
|
+
console.log(chalk.gray(` Suggestions: ${strategic.suggestions}`));
|
|
1648
|
+
}
|
|
1649
|
+
// Write strategic decision to journal
|
|
1650
|
+
const journalPath = path.join(projectRoot, ".jfl", "journal");
|
|
1651
|
+
if (fs.existsSync(journalPath)) {
|
|
1652
|
+
const entry = {
|
|
1653
|
+
v: 2, ts: new Date().toISOString(), session: "peter-parker",
|
|
1654
|
+
type: "decision", status: "complete",
|
|
1655
|
+
title: "Layer 3: Strategic reasoning",
|
|
1656
|
+
summary: strategic.reasoning || strategicText.slice(0, 200),
|
|
1657
|
+
detail: strategicText,
|
|
1658
|
+
};
|
|
1659
|
+
const files = fs.readdirSync(journalPath).filter(f => f.endsWith(".jsonl")).sort();
|
|
1660
|
+
const latestJournal = files[files.length - 1];
|
|
1661
|
+
if (latestJournal) {
|
|
1662
|
+
fs.appendFileSync(path.join(journalPath, latestJournal), "\n" + JSON.stringify(entry));
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
}
|
|
1666
|
+
}
|
|
1667
|
+
catch { /* non-JSON response, that's fine */ }
|
|
1668
|
+
}
|
|
1669
|
+
catch (err) {
|
|
1670
|
+
console.log(chalk.yellow(` Strategic reasoning failed: ${err.message}`));
|
|
1671
|
+
}
|
|
1672
|
+
console.log();
|
|
1673
|
+
// Check for scope:impact events that should trigger downstream agents
|
|
1674
|
+
const impactTriggered = orchestrator.getImpactTriggeredAgents();
|
|
1675
|
+
if (impactTriggered.length > 0) {
|
|
1676
|
+
console.log(chalk.cyan(" Scope impact events detected:"));
|
|
1677
|
+
for (const { agent, impactPattern } of impactTriggered) {
|
|
1678
|
+
console.log(chalk.gray(` • ${agent.name} should react to: ${impactPattern}`));
|
|
1679
|
+
}
|
|
1680
|
+
console.log();
|
|
1681
|
+
}
|
|
1682
|
+
// Schedule next agent using meta-orchestrator
|
|
1683
|
+
const decision = orchestrator.scheduleNext();
|
|
1684
|
+
if (!decision) {
|
|
1685
|
+
console.log(chalk.yellow(" No agent available to schedule."));
|
|
1686
|
+
return;
|
|
1687
|
+
}
|
|
1688
|
+
console.log(chalk.bold(` Scheduled: ${decision.agent.name}`));
|
|
1689
|
+
console.log(chalk.gray(` Reason: ${decision.reason}`));
|
|
1690
|
+
if (decision.impactPattern) {
|
|
1691
|
+
console.log(chalk.gray(` Triggered by: ${decision.impactPattern}`));
|
|
1692
|
+
}
|
|
1693
|
+
if (decision.emaReward !== undefined) {
|
|
1694
|
+
console.log(chalk.gray(` EMA Reward: ${decision.emaReward.toFixed(4)}`));
|
|
1695
|
+
}
|
|
1696
|
+
console.log();
|
|
1697
|
+
// Run autoresearch for stale agents
|
|
1698
|
+
if (staleAgents.length > 0) {
|
|
1699
|
+
console.log(chalk.cyan(` Running autoresearch for ${staleAgents.length} stale agent(s)...\n`));
|
|
1700
|
+
for (const agentName of staleAgents) {
|
|
1701
|
+
console.log(chalk.bold(`\n ── ${agentName} ${"─".repeat(45)}\n`));
|
|
1702
|
+
await agentRun(projectRoot, agentName); // Use config.rounds (default 50)
|
|
1703
|
+
}
|
|
1704
|
+
}
|
|
1705
|
+
// Post summary event
|
|
1706
|
+
await postHubEvent(projectRoot, "peter:daily-complete", {
|
|
1707
|
+
total_agents: agents.length,
|
|
1708
|
+
stale_agents: staleAgents,
|
|
1709
|
+
active_agents: activeAgents,
|
|
1710
|
+
impact_triggered: impactTriggered.map(t => t.agent.name),
|
|
1711
|
+
scheduled: decision.agent.name,
|
|
1712
|
+
reason: decision.reason,
|
|
1713
|
+
});
|
|
1714
|
+
console.log(chalk.green("\n Daily loop complete.\n"));
|
|
1715
|
+
}
|
|
1716
|
+
async function agentSwarm(projectRoot, rounds) {
|
|
1717
|
+
const { MetaOrchestrator } = await import("../lib/meta-orchestrator.js");
|
|
1718
|
+
const orchestrator = new MetaOrchestrator(projectRoot);
|
|
1719
|
+
const agents = orchestrator.getAgents();
|
|
1720
|
+
if (agents.length === 0) {
|
|
1721
|
+
console.log(chalk.yellow("\n No agents configured."));
|
|
1722
|
+
console.log(chalk.gray(" Run: jfl peter agent create\n"));
|
|
1723
|
+
return;
|
|
1724
|
+
}
|
|
1725
|
+
console.log(chalk.bold(`\n Agent Swarm: ${agents.length} agents, ${rounds} rounds total\n`));
|
|
1726
|
+
for (const agent of agents) {
|
|
1727
|
+
console.log(chalk.gray(` - ${agent.name} (${agent.metric})`));
|
|
1728
|
+
}
|
|
1729
|
+
console.log();
|
|
1730
|
+
const result = await orchestrator.runSwarm(rounds, (agent, round, reward, reason) => {
|
|
1731
|
+
const emoji = reward > 0 ? chalk.green("+") : reward < 0 ? chalk.red("-") : chalk.gray("=");
|
|
1732
|
+
console.log(chalk.gray(` [${round}/${rounds}] ${agent} → ${emoji}${Math.abs(reward).toFixed(4)} (${reason})`));
|
|
1733
|
+
});
|
|
1734
|
+
console.log(chalk.bold(`\n ── Swarm Complete ${"─".repeat(38)}\n`));
|
|
1735
|
+
const stats = orchestrator.getStats();
|
|
1736
|
+
console.log(chalk.gray(` Total rounds: ${stats.totalRounds}`));
|
|
1737
|
+
console.log(chalk.gray(` Avg EMA reward: ${stats.avgEmaReward.toFixed(4)}`));
|
|
1738
|
+
console.log(chalk.gray(` Overall win rate: ${(stats.overallWinRate * 100).toFixed(1)}%`));
|
|
1739
|
+
if (stats.bestAgent) {
|
|
1740
|
+
console.log(chalk.green(` Best agent: ${stats.bestAgent.name} (EMA: ${stats.bestAgent.emaReward.toFixed(4)})`));
|
|
1741
|
+
}
|
|
1742
|
+
console.log(chalk.bold("\n Per-Agent Results:\n"));
|
|
1743
|
+
for (const [name, data] of Object.entries(result.perAgent)) {
|
|
1744
|
+
console.log(chalk.cyan(` ${name}: ${data.rounds} rounds, total delta: ${data.totalReward > 0 ? "+" : ""}${data.totalReward.toFixed(4)}`));
|
|
1745
|
+
}
|
|
1746
|
+
console.log();
|
|
1747
|
+
}
|
|
1748
|
+
// ============================================================================
|
|
1749
|
+
// Synthesis — distill journals + events into product context for agents
|
|
1750
|
+
// ============================================================================
|
|
1751
|
+
async function runSynthesis(projectRoot) {
|
|
1752
|
+
console.log(chalk.bold("\n Peter Parker - Product Context Synthesis\n"));
|
|
1753
|
+
const { StratusClient } = await import("../lib/stratus-client.js");
|
|
1754
|
+
const stratus = process.env.STRATUS_API_KEY
|
|
1755
|
+
? new StratusClient({ apiKey: process.env.STRATUS_API_KEY })
|
|
1756
|
+
: null;
|
|
1757
|
+
if (!stratus) {
|
|
1758
|
+
console.log(chalk.red(" STRATUS_API_KEY required for synthesis"));
|
|
1759
|
+
return;
|
|
1760
|
+
}
|
|
1761
|
+
// 1. Read recent journals (last 7 days)
|
|
1762
|
+
const journalDir = path.join(projectRoot, ".jfl", "journal");
|
|
1763
|
+
let journalEntries = [];
|
|
1764
|
+
if (fs.existsSync(journalDir)) {
|
|
1765
|
+
const files = fs.readdirSync(journalDir).filter(f => f.endsWith(".jsonl"));
|
|
1766
|
+
for (const file of files.slice(-10)) { // Last 10 journal files
|
|
1767
|
+
const content = fs.readFileSync(path.join(journalDir, file), "utf-8").trim();
|
|
1768
|
+
if (content)
|
|
1769
|
+
journalEntries.push(...content.split("\n").slice(-20)); // Last 20 entries per file
|
|
1770
|
+
}
|
|
1771
|
+
}
|
|
1772
|
+
console.log(chalk.gray(` Read ${journalEntries.length} journal entries`));
|
|
1773
|
+
// 2. Read recent events
|
|
1774
|
+
const eventsPath = path.join(projectRoot, ".jfl", "service-events.jsonl");
|
|
1775
|
+
let events = [];
|
|
1776
|
+
if (fs.existsSync(eventsPath)) {
|
|
1777
|
+
events = fs.readFileSync(eventsPath, "utf-8").trim().split("\n").slice(-30); // Last 30 events
|
|
1778
|
+
}
|
|
1779
|
+
console.log(chalk.gray(` Read ${events.length} events`));
|
|
1780
|
+
// 3. Read agent results from training buffer
|
|
1781
|
+
const bufferPath = path.join(projectRoot, ".jfl", "training-buffer.jsonl");
|
|
1782
|
+
let tuples = [];
|
|
1783
|
+
if (fs.existsSync(bufferPath)) {
|
|
1784
|
+
tuples = fs.readFileSync(bufferPath, "utf-8").trim().split("\n").slice(-20);
|
|
1785
|
+
}
|
|
1786
|
+
console.log(chalk.gray(` Read ${tuples.length} training tuples`));
|
|
1787
|
+
// 4. Read current agent configs
|
|
1788
|
+
const { listAgentConfigs, loadAgentConfig } = await import("../lib/agent-config.js");
|
|
1789
|
+
const agentNames = listAgentConfigs(projectRoot);
|
|
1790
|
+
const configs = agentNames.map(name => { try {
|
|
1791
|
+
return loadAgentConfig(projectRoot, name);
|
|
1792
|
+
}
|
|
1793
|
+
catch {
|
|
1794
|
+
return null;
|
|
1795
|
+
} }).filter(Boolean);
|
|
1796
|
+
const agentSummary = configs.map((c) => `${c.name}: ${c.metric} (${c.direction}), target: ${c.target_repo || "self"}`).join("\n");
|
|
1797
|
+
// 5. Send to Stratus for synthesis
|
|
1798
|
+
console.log(chalk.gray("\n Synthesizing with Stratus...\n"));
|
|
1799
|
+
const prompt = `You are Peter Parker, the orchestrator for a software product portfolio.
|
|
1800
|
+
|
|
1801
|
+
Your job: read the recent activity (journals, events, experiment results) and produce a PRODUCT CONTEXT document that tells scoped RL agents what the product is, what's been happening, and what to focus on.
|
|
1802
|
+
|
|
1803
|
+
## Current Agents
|
|
1804
|
+
${agentSummary}
|
|
1805
|
+
|
|
1806
|
+
## Recent Journal Entries (last 7 days)
|
|
1807
|
+
${journalEntries.slice(-15).map(e => e.slice(0, 200)).join("\n")}
|
|
1808
|
+
|
|
1809
|
+
## Recent Events
|
|
1810
|
+
${events.slice(-15).join("\n")}
|
|
1811
|
+
|
|
1812
|
+
## Recent Experiment Results
|
|
1813
|
+
${tuples.slice(-10).join("\n")}
|
|
1814
|
+
|
|
1815
|
+
---
|
|
1816
|
+
|
|
1817
|
+
Produce a concise product-context.md with these sections:
|
|
1818
|
+
1. **Product State** — what is this product, what's working, what's broken
|
|
1819
|
+
2. **Recent Activity** — what the team has been building/fixing (distilled from journals)
|
|
1820
|
+
3. **Agent Guidance** — for each active agent, specific guidance based on recent context (e.g. "cli-speed: startup is already fast, focus on subcommand latency")
|
|
1821
|
+
4. **Priority Shifts** — any metrics that should be deprioritized or new metrics to consider
|
|
1822
|
+
5. **Open Questions** — things that need human input
|
|
1823
|
+
|
|
1824
|
+
Be concise. This document is consumed by agents, not humans. Skip fluff.`;
|
|
1825
|
+
try {
|
|
1826
|
+
const response = await stratus.reason(prompt, { maxTokens: 1500, temperature: 0.3 });
|
|
1827
|
+
const synthesis = response.choices[0]?.message?.content || "";
|
|
1828
|
+
if (synthesis) {
|
|
1829
|
+
const outputPath = path.join(projectRoot, ".jfl", "product-context.md");
|
|
1830
|
+
fs.writeFileSync(outputPath, `# Product Context\n\n_Synthesized by Peter Parker at ${new Date().toISOString()}_\n\n${synthesis}\n`);
|
|
1831
|
+
console.log(chalk.green(` ✓ Product context written to .jfl/product-context.md`));
|
|
1832
|
+
console.log(chalk.gray(` (${synthesis.length} chars)\n`));
|
|
1833
|
+
}
|
|
1834
|
+
}
|
|
1835
|
+
catch (err) {
|
|
1836
|
+
console.log(chalk.red(` Synthesis failed: ${err.message}`));
|
|
1837
|
+
}
|
|
1838
|
+
}
|
|
1839
|
+
// ============================================================================
|
|
1840
|
+
// Review — check autoresearch branches, audit with Stratus, prepare PRs
|
|
1841
|
+
// ============================================================================
|
|
1842
|
+
async function runReview(projectRoot) {
|
|
1843
|
+
console.log(chalk.bold("\n Peter Parker - Autoresearch Review\n"));
|
|
1844
|
+
const { spawnSync } = await import("child_process");
|
|
1845
|
+
// Find session branches on remote
|
|
1846
|
+
const result = spawnSync("git", ["branch", "-r", "--list", "origin/session/*"], { cwd: projectRoot, encoding: "utf-8" });
|
|
1847
|
+
const branches = (result.stdout || "").trim().split("\n").map(b => b.trim()).filter(Boolean);
|
|
1848
|
+
if (branches.length === 0) {
|
|
1849
|
+
console.log(chalk.yellow(" No autoresearch branches found.\n"));
|
|
1850
|
+
return;
|
|
1851
|
+
}
|
|
1852
|
+
console.log(chalk.gray(` Found ${branches.length} session branch(es):\n`));
|
|
1853
|
+
for (const branch of branches) {
|
|
1854
|
+
const shortBranch = branch.replace("origin/", "");
|
|
1855
|
+
// Get diff stats
|
|
1856
|
+
const diffStat = spawnSync("git", ["diff", "--stat", `origin/main...${branch}`], { cwd: projectRoot, encoding: "utf-8" });
|
|
1857
|
+
const logResult = spawnSync("git", ["log", "--oneline", `origin/main..${branch}`], { cwd: projectRoot, encoding: "utf-8" });
|
|
1858
|
+
const commits = (logResult.stdout || "").trim().split("\n").filter(Boolean);
|
|
1859
|
+
console.log(chalk.cyan(` ${shortBranch}`));
|
|
1860
|
+
console.log(chalk.gray(` ${commits.length} commits`));
|
|
1861
|
+
if (diffStat.stdout) {
|
|
1862
|
+
const lastLine = diffStat.stdout.trim().split("\n").pop() || "";
|
|
1863
|
+
console.log(chalk.gray(` ${lastLine.trim()}`));
|
|
1864
|
+
}
|
|
1865
|
+
console.log();
|
|
1866
|
+
}
|
|
1867
|
+
console.log(chalk.gray(" To create PRs from these branches:"));
|
|
1868
|
+
console.log(chalk.gray(" gh pr create --base main --head <branch> --title '...'\n"));
|
|
1869
|
+
}
|
|
846
1870
|
export async function peterCommand(action, options = {}) {
|
|
847
1871
|
const projectRoot = process.cwd();
|
|
1872
|
+
// Handle "agent" subcommand
|
|
1873
|
+
if (action === "agent") {
|
|
1874
|
+
const subAction = options.name || options.task; // name is the subcommand, task might be agent name
|
|
1875
|
+
if (subAction === "create") {
|
|
1876
|
+
await agentCreate(projectRoot);
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
else if (subAction === "list") {
|
|
1880
|
+
await agentList(projectRoot);
|
|
1881
|
+
return;
|
|
1882
|
+
}
|
|
1883
|
+
else if (subAction === "run") {
|
|
1884
|
+
// jfl peter agent run <name> --rounds N
|
|
1885
|
+
// The agent name would be in a different position
|
|
1886
|
+
console.log(chalk.yellow("\n Usage: jfl peter agent run <name> --rounds N\n"));
|
|
1887
|
+
return;
|
|
1888
|
+
}
|
|
1889
|
+
else if (subAction === "swarm") {
|
|
1890
|
+
const rounds = parseInt(options.rounds || "20", 10);
|
|
1891
|
+
await agentSwarm(projectRoot, rounds);
|
|
1892
|
+
return;
|
|
1893
|
+
}
|
|
1894
|
+
else if (subAction) {
|
|
1895
|
+
// Assume it's an agent name for "run"
|
|
1896
|
+
// Use CLI override if provided, otherwise use config.rounds (default 50)
|
|
1897
|
+
const roundsOverride = options.rounds ? parseInt(options.rounds, 10) : undefined;
|
|
1898
|
+
await agentRun(projectRoot, subAction, roundsOverride);
|
|
1899
|
+
return;
|
|
1900
|
+
}
|
|
1901
|
+
// Show agent help
|
|
1902
|
+
console.log(chalk.bold("\n Peter Parker - Scoped Agent Commands\n"));
|
|
1903
|
+
console.log(chalk.gray(" Commands:"));
|
|
1904
|
+
console.log(" jfl peter agent create Interactive agent creation");
|
|
1905
|
+
console.log(" jfl peter agent list List configured agents");
|
|
1906
|
+
console.log(" jfl peter agent run <name> [--rounds N] Run a specific agent");
|
|
1907
|
+
console.log(" jfl peter agent swarm [--rounds N] Run all agents with meta-orchestrator");
|
|
1908
|
+
console.log();
|
|
1909
|
+
return;
|
|
1910
|
+
}
|
|
848
1911
|
switch (action) {
|
|
849
1912
|
case "setup": {
|
|
850
1913
|
let profile = "balanced";
|
|
@@ -877,7 +1940,8 @@ export async function peterCommand(action, options = {}) {
|
|
|
877
1940
|
case "experiment": {
|
|
878
1941
|
if (options.mode === "autoresearch") {
|
|
879
1942
|
const rounds = parseInt(options.rounds || "5", 10);
|
|
880
|
-
|
|
1943
|
+
const budget = options.budget ? parseFloat(options.budget) : undefined;
|
|
1944
|
+
await runAutoresearch(projectRoot, { rounds, budget, usePi: options.pi });
|
|
881
1945
|
}
|
|
882
1946
|
else {
|
|
883
1947
|
await runExperiment(projectRoot);
|
|
@@ -886,7 +1950,37 @@ export async function peterCommand(action, options = {}) {
|
|
|
886
1950
|
}
|
|
887
1951
|
case "autoresearch": {
|
|
888
1952
|
const rounds = parseInt(options.rounds || "5", 10);
|
|
889
|
-
|
|
1953
|
+
const budget = options.budget ? parseFloat(options.budget) : undefined;
|
|
1954
|
+
await runAutoresearch(projectRoot, { rounds, budget, usePi: options.pi });
|
|
1955
|
+
break;
|
|
1956
|
+
}
|
|
1957
|
+
case "telemetry": {
|
|
1958
|
+
await runTelemetryAgent(projectRoot);
|
|
1959
|
+
break;
|
|
1960
|
+
}
|
|
1961
|
+
case "sentinel": {
|
|
1962
|
+
await runSentinelReview(projectRoot);
|
|
1963
|
+
break;
|
|
1964
|
+
}
|
|
1965
|
+
case "metrics": {
|
|
1966
|
+
await showMetrics(projectRoot);
|
|
1967
|
+
break;
|
|
1968
|
+
}
|
|
1969
|
+
case "daily": {
|
|
1970
|
+
await runDailyLoop(projectRoot);
|
|
1971
|
+
break;
|
|
1972
|
+
}
|
|
1973
|
+
case "nightly": {
|
|
1974
|
+
// Alias for daily
|
|
1975
|
+
await runDailyLoop(projectRoot);
|
|
1976
|
+
break;
|
|
1977
|
+
}
|
|
1978
|
+
case "synthesize": {
|
|
1979
|
+
await runSynthesis(projectRoot);
|
|
1980
|
+
break;
|
|
1981
|
+
}
|
|
1982
|
+
case "review": {
|
|
1983
|
+
await runReview(projectRoot);
|
|
890
1984
|
break;
|
|
891
1985
|
}
|
|
892
1986
|
default: {
|
|
@@ -896,11 +1990,27 @@ export async function peterCommand(action, options = {}) {
|
|
|
896
1990
|
console.log(" jfl peter run [--task <task>] Run orchestrator");
|
|
897
1991
|
console.log(" jfl peter pr --task <task> Run + branch + PR");
|
|
898
1992
|
console.log(" jfl peter experiment Proactive: pick + execute next experiment");
|
|
899
|
-
console.log(" jfl peter
|
|
900
|
-
console.log("
|
|
1993
|
+
console.log(" jfl peter autoresearch [--rounds N] [--budget $] [--pi]");
|
|
1994
|
+
console.log(" Autoresearch mode with Pi runtime");
|
|
901
1995
|
console.log(" jfl peter status Show status + recent events");
|
|
902
1996
|
console.log(" jfl peter dashboard Live event stream dashboard");
|
|
903
1997
|
console.log();
|
|
1998
|
+
console.log(chalk.bold(" Pi-sky Runtime Options:\n"));
|
|
1999
|
+
console.log(" --budget <amount> Cost budget in USD (auto-downgrades model when exceeded)");
|
|
2000
|
+
console.log(" --pi Force Pi runtime (default: auto-detect)");
|
|
2001
|
+
console.log();
|
|
2002
|
+
console.log(chalk.bold(" Telemetry & RL:\n"));
|
|
2003
|
+
console.log(" jfl peter telemetry Run telemetry agent (platform digest)");
|
|
2004
|
+
console.log(" jfl peter sentinel Run Sentinel nightly review");
|
|
2005
|
+
console.log(" jfl peter metrics Show current platform metrics");
|
|
2006
|
+
console.log(" jfl peter daily Daily RL loop (check stale agents, schedule next)");
|
|
2007
|
+
console.log();
|
|
2008
|
+
console.log(chalk.bold(" Scoped Agents:\n"));
|
|
2009
|
+
console.log(" jfl peter agent create Interactive agent creation");
|
|
2010
|
+
console.log(" jfl peter agent list List configured agents");
|
|
2011
|
+
console.log(" jfl peter agent run <name> [--rounds N] Run a specific scoped agent");
|
|
2012
|
+
console.log(" jfl peter agent swarm [--rounds N] Run all agents with orchestrator");
|
|
2013
|
+
console.log();
|
|
904
2014
|
}
|
|
905
2015
|
}
|
|
906
2016
|
}
|