jfl 0.5.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/commands/context-hub.d.ts +1 -0
- package/dist/commands/context-hub.d.ts.map +1 -1
- package/dist/commands/context-hub.js +246 -2
- package/dist/commands/context-hub.js.map +1 -1
- package/dist/commands/peter.d.ts +2 -0
- package/dist/commands/peter.d.ts.map +1 -1
- package/dist/commands/peter.js +242 -52
- package/dist/commands/peter.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/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/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 +99 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/agent-session.d.ts.map +1 -1
- package/dist/lib/agent-session.js +12 -4
- package/dist/lib/agent-session.js.map +1 -1
- package/dist/lib/eval-snapshot.js +1 -1
- package/dist/lib/eval-snapshot.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 +16 -1
- package/dist/lib/policy-head.d.ts.map +1 -1
- package/dist/lib/policy-head.js +117 -19
- package/dist/lib/policy-head.js.map +1 -1
- 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/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/package.json +1 -1
- package/packages/pi/extensions/context.ts +88 -55
- package/packages/pi/extensions/hub-resolver.ts +63 -0
- package/packages/pi/extensions/index.ts +16 -3
- package/packages/pi/extensions/memory-tool.ts +9 -4
- package/packages/pi/extensions/session.ts +68 -16
- package/packages/pi/extensions/tool-renderers.ts +23 -8
- 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/template/.claude/settings.json +2 -15
- package/template/scripts/session/session-cleanup.sh +2 -11
- package/template/scripts/session/session-end-hub.sh +72 -0
- package/template/scripts/session/session-start-hub.sh +105 -0
- package/dist/dashboard-static/assets/index-B6b867Pv.js +0 -121
- package/dist/dashboard-static/assets/index-Y4BrqxV-.css +0 -1
package/dist/commands/peter.js
CHANGED
|
@@ -18,6 +18,7 @@ import { TrajectoryLoader } from "../lib/trajectory-loader.js";
|
|
|
18
18
|
import { readEvals } from "../lib/eval-store.js";
|
|
19
19
|
import { TrainingBuffer } from "../lib/training-buffer.js";
|
|
20
20
|
import { PolicyHeadInference } from "../lib/policy-head.js";
|
|
21
|
+
import { PiRpcBridge, CostMonitor, EventRouter } from "../lib/pi-sky/index.js";
|
|
21
22
|
function hasRalphTui() {
|
|
22
23
|
try {
|
|
23
24
|
execSync("which ralph-tui", { stdio: "ignore" });
|
|
@@ -27,6 +28,15 @@ function hasRalphTui() {
|
|
|
27
28
|
return false;
|
|
28
29
|
}
|
|
29
30
|
}
|
|
31
|
+
function hasPi() {
|
|
32
|
+
try {
|
|
33
|
+
execSync("which pi", { stdio: "ignore" });
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
30
40
|
function getAuthToken(projectRoot) {
|
|
31
41
|
const tokenPath = path.join(projectRoot, ".jfl", "context-hub.token");
|
|
32
42
|
if (fs.existsSync(tokenPath)) {
|
|
@@ -194,6 +204,108 @@ async function postHubEvent(projectRoot, eventType, data) {
|
|
|
194
204
|
console.log(chalk.gray(" PP: Warning - could not post event to hub"));
|
|
195
205
|
}
|
|
196
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
|
+
}
|
|
197
309
|
async function runWithPR(projectRoot, task) {
|
|
198
310
|
if (!task) {
|
|
199
311
|
console.log(chalk.yellow("\n --task is required for pr mode"));
|
|
@@ -612,20 +724,52 @@ Respond with ONLY a JSON array, no other text.`;
|
|
|
612
724
|
console.log(chalk.cyan(" Dispatching to Peter Parker PR workflow...\n"));
|
|
613
725
|
await runWithPR(projectRoot, proposal.task);
|
|
614
726
|
}
|
|
615
|
-
async function runAutoresearch(projectRoot,
|
|
727
|
+
async function runAutoresearch(projectRoot, options) {
|
|
728
|
+
const { rounds, budget, usePi } = options;
|
|
616
729
|
console.log(chalk.bold(`\n Peter Parker - Autoresearch Mode (${rounds} rounds)\n`));
|
|
617
730
|
console.log(chalk.gray(" Pattern: branch → change → eval → keep|revert → repeat"));
|
|
618
|
-
console.log(chalk.gray(" Only the winning experiment gets a PR
|
|
619
|
-
if (
|
|
620
|
-
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)"));
|
|
621
763
|
console.log(chalk.gray(" Install: bun install -g ralph-tui\n"));
|
|
622
764
|
return;
|
|
623
765
|
}
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
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
|
+
}
|
|
629
773
|
}
|
|
630
774
|
const loader = new TrajectoryLoader(projectRoot);
|
|
631
775
|
const evals = readEvals(projectRoot);
|
|
@@ -667,9 +811,26 @@ async function runAutoresearch(projectRoot, rounds) {
|
|
|
667
811
|
}))), 15);
|
|
668
812
|
const policyHead = new PolicyHeadInference(projectRoot);
|
|
669
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
|
+
}
|
|
670
831
|
const prompt = useMultiProposal
|
|
671
832
|
? `Autoresearch round ${round}/${rounds}. Suggest 3 specific improvements ranked by expected impact.
|
|
672
|
-
|
|
833
|
+
${actionGuidance}
|
|
673
834
|
Eval history:
|
|
674
835
|
${evalSummary}
|
|
675
836
|
|
|
@@ -681,7 +842,7 @@ ${results.map(r => `- Round ${r.round}: "${r.task}" → delta=${r.delta > 0 ? "+
|
|
|
681
842
|
|
|
682
843
|
Respond with ONLY a JSON array of 3 objects: [{"task": "...", "predicted_delta": 0.0-1.0, "reasoning": "...", "risk": "..."}, ...]`
|
|
683
844
|
: `Autoresearch round ${round}/${rounds}. Suggest ONE specific improvement.
|
|
684
|
-
|
|
845
|
+
${actionGuidance}
|
|
685
846
|
Eval history:
|
|
686
847
|
${evalSummary}
|
|
687
848
|
|
|
@@ -758,44 +919,56 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
758
919
|
console.log(chalk.red(` Failed to create branch ${branchName}`));
|
|
759
920
|
continue;
|
|
760
921
|
}
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
const prdPath = path.join(ralphDir, "autoresearch-task.json");
|
|
766
|
-
const prd = {
|
|
767
|
-
name: "Autoresearch Task",
|
|
768
|
-
branchName: `ralph/autoresearch-${Date.now()}`,
|
|
769
|
-
description: proposal.task,
|
|
770
|
-
userStories: [{
|
|
771
|
-
id: "US-001",
|
|
772
|
-
title: proposal.task.slice(0, 80),
|
|
773
|
-
description: proposal.task,
|
|
774
|
-
acceptanceCriteria: ["Task completed"],
|
|
775
|
-
priority: 1, passes: false, notes: "", dependsOn: [],
|
|
776
|
-
}],
|
|
777
|
-
metadata: { updatedAt: new Date().toISOString() },
|
|
778
|
-
};
|
|
779
|
-
fs.writeFileSync(prdPath, JSON.stringify(prd, null, 2));
|
|
780
|
-
const env = { ...process.env };
|
|
781
|
-
delete env.CLAUDECODE;
|
|
782
|
-
delete env.CLAUDE_CODE;
|
|
783
|
-
const child = spawn("claude", [
|
|
784
|
-
"--dangerously-skip-permissions",
|
|
785
|
-
"-p", proposal.task,
|
|
786
|
-
"--output-format", "text",
|
|
787
|
-
], {
|
|
788
|
-
cwd: projectRoot, stdio: "inherit", env,
|
|
789
|
-
});
|
|
790
|
-
child.on("error", () => { try {
|
|
791
|
-
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);
|
|
792
926
|
}
|
|
793
|
-
catch
|
|
794
|
-
|
|
795
|
-
fs.unlinkSync(prdPath);
|
|
927
|
+
catch (err) {
|
|
928
|
+
console.log(chalk.yellow(` Pi task failed: ${err.message}`));
|
|
796
929
|
}
|
|
797
|
-
|
|
798
|
-
|
|
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
|
+
}
|
|
799
972
|
const diffCheck = gitExec(["diff", "--quiet", "HEAD"], projectRoot);
|
|
800
973
|
const untrackedResult = spawnSync("git", ["ls-files", "--others", "--exclude-standard"], {
|
|
801
974
|
cwd: projectRoot, encoding: "utf-8", stdio: "pipe",
|
|
@@ -961,6 +1134,14 @@ Suggest the SINGLE highest-value change. JSON format:
|
|
|
961
1134
|
}
|
|
962
1135
|
}
|
|
963
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
|
+
}
|
|
964
1145
|
console.log();
|
|
965
1146
|
}
|
|
966
1147
|
// ============================================================================
|
|
@@ -1060,7 +1241,8 @@ async function agentRun(projectRoot, agentName, roundsOverride) {
|
|
|
1060
1241
|
// Allow override via CLI for debugging/testing
|
|
1061
1242
|
const rounds = roundsOverride ?? config.rounds ?? 50;
|
|
1062
1243
|
// Get scope_files for display
|
|
1063
|
-
const
|
|
1244
|
+
const rawScopeFiles = config.constraints.scope_files || config.constraints.files_in_scope || [];
|
|
1245
|
+
const displayScopeFiles = Array.isArray(rawScopeFiles) ? rawScopeFiles : [String(rawScopeFiles)];
|
|
1064
1246
|
const scopeFilesDisplay = displayScopeFiles.slice(0, 3).join(", ") + (displayScopeFiles.length > 3 ? "..." : "");
|
|
1065
1247
|
console.log(chalk.bold(`\n Running Scoped Agent: ${agentName} (${rounds} rounds)\n`));
|
|
1066
1248
|
console.log(chalk.gray(` Metric: ${config.metric} (${config.direction})`));
|
|
@@ -1091,7 +1273,8 @@ async function agentRun(projectRoot, agentName, roundsOverride) {
|
|
|
1091
1273
|
? new StratusClient({ apiKey: process.env.STRATUS_API_KEY })
|
|
1092
1274
|
: null;
|
|
1093
1275
|
// Get scope_files from config (Karpathy pattern: focused file list)
|
|
1094
|
-
const
|
|
1276
|
+
const rawScope = config.constraints.scope_files || config.constraints.files_in_scope || [];
|
|
1277
|
+
const scopeFiles = Array.isArray(rawScope) ? rawScope : [String(rawScope)];
|
|
1095
1278
|
const scopeFilesStr = scopeFiles.slice(0, 5).join(", ");
|
|
1096
1279
|
for (let round = 1; round <= rounds; round++) {
|
|
1097
1280
|
console.log(chalk.bold(`\n ── Round ${round}/${rounds} ${"─".repeat(40)}\n`));
|
|
@@ -1757,7 +1940,8 @@ export async function peterCommand(action, options = {}) {
|
|
|
1757
1940
|
case "experiment": {
|
|
1758
1941
|
if (options.mode === "autoresearch") {
|
|
1759
1942
|
const rounds = parseInt(options.rounds || "5", 10);
|
|
1760
|
-
|
|
1943
|
+
const budget = options.budget ? parseFloat(options.budget) : undefined;
|
|
1944
|
+
await runAutoresearch(projectRoot, { rounds, budget, usePi: options.pi });
|
|
1761
1945
|
}
|
|
1762
1946
|
else {
|
|
1763
1947
|
await runExperiment(projectRoot);
|
|
@@ -1766,7 +1950,8 @@ export async function peterCommand(action, options = {}) {
|
|
|
1766
1950
|
}
|
|
1767
1951
|
case "autoresearch": {
|
|
1768
1952
|
const rounds = parseInt(options.rounds || "5", 10);
|
|
1769
|
-
|
|
1953
|
+
const budget = options.budget ? parseFloat(options.budget) : undefined;
|
|
1954
|
+
await runAutoresearch(projectRoot, { rounds, budget, usePi: options.pi });
|
|
1770
1955
|
break;
|
|
1771
1956
|
}
|
|
1772
1957
|
case "telemetry": {
|
|
@@ -1805,10 +1990,15 @@ export async function peterCommand(action, options = {}) {
|
|
|
1805
1990
|
console.log(" jfl peter run [--task <task>] Run orchestrator");
|
|
1806
1991
|
console.log(" jfl peter pr --task <task> Run + branch + PR");
|
|
1807
1992
|
console.log(" jfl peter experiment Proactive: pick + execute next experiment");
|
|
1808
|
-
console.log(" jfl peter autoresearch [--rounds N]
|
|
1993
|
+
console.log(" jfl peter autoresearch [--rounds N] [--budget $] [--pi]");
|
|
1994
|
+
console.log(" Autoresearch mode with Pi runtime");
|
|
1809
1995
|
console.log(" jfl peter status Show status + recent events");
|
|
1810
1996
|
console.log(" jfl peter dashboard Live event stream dashboard");
|
|
1811
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();
|
|
1812
2002
|
console.log(chalk.bold(" Telemetry & RL:\n"));
|
|
1813
2003
|
console.log(" jfl peter telemetry Run telemetry agent (platform digest)");
|
|
1814
2004
|
console.log(" jfl peter sentinel Run Sentinel nightly review");
|