jfl 0.9.6 → 0.9.7

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.
Files changed (206) hide show
  1. package/dist/commands/agents.js +1 -1
  2. package/dist/commands/agents.js.map +1 -1
  3. package/dist/commands/context-hub.d.ts.map +1 -1
  4. package/dist/commands/context-hub.js +77 -18
  5. package/dist/commands/context-hub.js.map +1 -1
  6. package/dist/commands/deploy.js +1 -1
  7. package/dist/commands/deploy.js.map +1 -1
  8. package/dist/commands/feedback.js +1 -1
  9. package/dist/commands/feedback.js.map +1 -1
  10. package/dist/commands/hud.js +1 -1
  11. package/dist/commands/hud.js.map +1 -1
  12. package/dist/commands/init-from-service.js +1 -1
  13. package/dist/commands/init-from-service.js.map +1 -1
  14. package/dist/commands/init.js +1 -1
  15. package/dist/commands/init.js.map +1 -1
  16. package/dist/commands/login.d.ts +2 -13
  17. package/dist/commands/login.d.ts.map +1 -1
  18. package/dist/commands/login.js +6 -44
  19. package/dist/commands/login.js.map +1 -1
  20. package/dist/commands/organize.d.ts +16 -0
  21. package/dist/commands/organize.d.ts.map +1 -0
  22. package/dist/commands/organize.js +334 -0
  23. package/dist/commands/organize.js.map +1 -0
  24. package/dist/commands/peter.d.ts.map +1 -1
  25. package/dist/commands/peter.js +273 -0
  26. package/dist/commands/peter.js.map +1 -1
  27. package/dist/commands/pi.d.ts.map +1 -1
  28. package/dist/commands/pi.js +8 -2
  29. package/dist/commands/pi.js.map +1 -1
  30. package/dist/commands/repair.js +1 -1
  31. package/dist/commands/repair.js.map +1 -1
  32. package/dist/commands/setup.d.ts.map +1 -1
  33. package/dist/commands/setup.js +113 -45
  34. package/dist/commands/setup.js.map +1 -1
  35. package/dist/commands/status.d.ts.map +1 -1
  36. package/dist/commands/status.js +4 -4
  37. package/dist/commands/status.js.map +1 -1
  38. package/dist/index.d.ts +0 -6
  39. package/dist/index.d.ts.map +1 -1
  40. package/dist/index.js +60 -19
  41. package/dist/index.js.map +1 -1
  42. package/dist/lib/agent-config.d.ts.map +1 -1
  43. package/dist/lib/agent-config.js +24 -2
  44. package/dist/lib/agent-config.js.map +1 -1
  45. package/dist/lib/hub-health.d.ts.map +1 -1
  46. package/dist/lib/hub-health.js +14 -2
  47. package/dist/lib/hub-health.js.map +1 -1
  48. package/dist/lib/resource-optimizer-middleware.d.ts.map +1 -1
  49. package/dist/lib/resource-optimizer-middleware.js +8 -2
  50. package/dist/lib/resource-optimizer-middleware.js.map +1 -1
  51. package/dist/lib/telemetry.d.ts.map +1 -1
  52. package/dist/lib/telemetry.js +13 -12
  53. package/dist/lib/telemetry.js.map +1 -1
  54. package/dist/utils/auth-status.d.ts +21 -0
  55. package/dist/utils/auth-status.d.ts.map +1 -0
  56. package/dist/utils/auth-status.js +53 -0
  57. package/dist/utils/auth-status.js.map +1 -0
  58. package/package.json +3 -2
  59. package/packages/pi/dist/agent-grid.d.ts +24 -0
  60. package/packages/pi/dist/agent-grid.d.ts.map +1 -0
  61. package/packages/pi/dist/agent-grid.js +162 -0
  62. package/packages/pi/dist/agent-grid.js.map +1 -0
  63. package/packages/pi/dist/agent-names.d.ts +43 -0
  64. package/packages/pi/dist/agent-names.d.ts.map +1 -0
  65. package/packages/pi/dist/agent-names.js +156 -0
  66. package/packages/pi/dist/agent-names.js.map +1 -0
  67. package/packages/pi/dist/autoresearch.d.ts +15 -0
  68. package/packages/pi/dist/autoresearch.d.ts.map +1 -0
  69. package/packages/pi/dist/autoresearch.js +372 -0
  70. package/packages/pi/dist/autoresearch.js.map +1 -0
  71. package/packages/pi/dist/bookmarks.d.ts +15 -0
  72. package/packages/pi/dist/bookmarks.d.ts.map +1 -0
  73. package/packages/pi/dist/bookmarks.js +77 -0
  74. package/packages/pi/dist/bookmarks.js.map +1 -0
  75. package/packages/pi/dist/context.d.ts +17 -0
  76. package/packages/pi/dist/context.d.ts.map +1 -0
  77. package/packages/pi/dist/context.js +152 -0
  78. package/packages/pi/dist/context.js.map +1 -0
  79. package/packages/pi/dist/crm-tool.d.ts +12 -0
  80. package/packages/pi/dist/crm-tool.d.ts.map +1 -0
  81. package/packages/pi/dist/crm-tool.js +58 -0
  82. package/packages/pi/dist/crm-tool.js.map +1 -0
  83. package/packages/pi/dist/eval-tool.d.ts +11 -0
  84. package/packages/pi/dist/eval-tool.d.ts.map +1 -0
  85. package/packages/pi/dist/eval-tool.js +188 -0
  86. package/packages/pi/dist/eval-tool.js.map +1 -0
  87. package/packages/pi/dist/eval.d.ts +12 -0
  88. package/packages/pi/dist/eval.d.ts.map +1 -0
  89. package/packages/pi/dist/eval.js +43 -0
  90. package/packages/pi/dist/eval.js.map +1 -0
  91. package/packages/pi/dist/footer.d.ts +20 -0
  92. package/packages/pi/dist/footer.d.ts.map +1 -0
  93. package/packages/pi/dist/footer.js +222 -0
  94. package/packages/pi/dist/footer.js.map +1 -0
  95. package/packages/pi/dist/header.d.ts +17 -0
  96. package/packages/pi/dist/header.d.ts.map +1 -0
  97. package/packages/pi/dist/header.js +156 -0
  98. package/packages/pi/dist/header.js.map +1 -0
  99. package/packages/pi/dist/hub-resolver.d.ts +11 -0
  100. package/packages/pi/dist/hub-resolver.d.ts.map +1 -0
  101. package/packages/pi/dist/hub-resolver.js +58 -0
  102. package/packages/pi/dist/hub-resolver.js.map +1 -0
  103. package/packages/pi/dist/hub-tools.d.ts +14 -0
  104. package/packages/pi/dist/hub-tools.d.ts.map +1 -0
  105. package/packages/pi/dist/hub-tools.js +266 -0
  106. package/packages/pi/dist/hub-tools.js.map +1 -0
  107. package/packages/pi/dist/hud-tool.d.ts +17 -0
  108. package/packages/pi/dist/hud-tool.d.ts.map +1 -0
  109. package/packages/pi/dist/hud-tool.js +297 -0
  110. package/packages/pi/dist/hud-tool.js.map +1 -0
  111. package/packages/pi/dist/index.d.ts +12 -0
  112. package/packages/pi/dist/index.d.ts.map +1 -0
  113. package/packages/pi/dist/index.js +436 -0
  114. package/packages/pi/dist/index.js.map +1 -0
  115. package/packages/pi/dist/jfl-resolve.d.ts +29 -0
  116. package/packages/pi/dist/jfl-resolve.d.ts.map +1 -0
  117. package/packages/pi/dist/jfl-resolve.js +89 -0
  118. package/packages/pi/dist/jfl-resolve.js.map +1 -0
  119. package/packages/pi/dist/journal.d.ts +23 -0
  120. package/packages/pi/dist/journal.d.ts.map +1 -0
  121. package/packages/pi/dist/journal.js +250 -0
  122. package/packages/pi/dist/journal.js.map +1 -0
  123. package/packages/pi/dist/map-bridge.d.ts +20 -0
  124. package/packages/pi/dist/map-bridge.d.ts.map +1 -0
  125. package/packages/pi/dist/map-bridge.js +181 -0
  126. package/packages/pi/dist/map-bridge.js.map +1 -0
  127. package/packages/pi/dist/memory-tool.d.ts +11 -0
  128. package/packages/pi/dist/memory-tool.d.ts.map +1 -0
  129. package/packages/pi/dist/memory-tool.js +148 -0
  130. package/packages/pi/dist/memory-tool.js.map +1 -0
  131. package/packages/pi/dist/notifications.d.ts +15 -0
  132. package/packages/pi/dist/notifications.d.ts.map +1 -0
  133. package/packages/pi/dist/notifications.js +65 -0
  134. package/packages/pi/dist/notifications.js.map +1 -0
  135. package/packages/pi/dist/onboarding-v1.d.ts +15 -0
  136. package/packages/pi/dist/onboarding-v1.d.ts.map +1 -0
  137. package/packages/pi/dist/onboarding-v1.js +417 -0
  138. package/packages/pi/dist/onboarding-v1.js.map +1 -0
  139. package/packages/pi/dist/onboarding-v2.d.ts +18 -0
  140. package/packages/pi/dist/onboarding-v2.d.ts.map +1 -0
  141. package/packages/pi/dist/onboarding-v2.js +402 -0
  142. package/packages/pi/dist/onboarding-v2.js.map +1 -0
  143. package/packages/pi/dist/onboarding-v3.d.ts +13 -0
  144. package/packages/pi/dist/onboarding-v3.d.ts.map +1 -0
  145. package/packages/pi/dist/onboarding-v3.js +581 -0
  146. package/packages/pi/dist/onboarding-v3.js.map +1 -0
  147. package/packages/pi/dist/peter-parker.d.ts +12 -0
  148. package/packages/pi/dist/peter-parker.d.ts.map +1 -0
  149. package/packages/pi/dist/peter-parker.js +162 -0
  150. package/packages/pi/dist/peter-parker.js.map +1 -0
  151. package/packages/pi/dist/pivot-tool.d.ts +11 -0
  152. package/packages/pi/dist/pivot-tool.d.ts.map +1 -0
  153. package/packages/pi/dist/pivot-tool.js +56 -0
  154. package/packages/pi/dist/pivot-tool.js.map +1 -0
  155. package/packages/pi/dist/policy-head-tool.d.ts +15 -0
  156. package/packages/pi/dist/policy-head-tool.d.ts.map +1 -0
  157. package/packages/pi/dist/policy-head-tool.js +220 -0
  158. package/packages/pi/dist/policy-head-tool.js.map +1 -0
  159. package/packages/pi/dist/portfolio-bridge.d.ts +12 -0
  160. package/packages/pi/dist/portfolio-bridge.d.ts.map +1 -0
  161. package/packages/pi/dist/portfolio-bridge.js +81 -0
  162. package/packages/pi/dist/portfolio-bridge.js.map +1 -0
  163. package/packages/pi/dist/service-skills.d.ts +15 -0
  164. package/packages/pi/dist/service-skills.d.ts.map +1 -0
  165. package/packages/pi/dist/service-skills.js +198 -0
  166. package/packages/pi/dist/service-skills.js.map +1 -0
  167. package/packages/pi/dist/session.d.ts +24 -0
  168. package/packages/pi/dist/session.d.ts.map +1 -0
  169. package/packages/pi/dist/session.js +394 -0
  170. package/packages/pi/dist/session.js.map +1 -0
  171. package/packages/pi/dist/shortcuts.d.ts +11 -0
  172. package/packages/pi/dist/shortcuts.d.ts.map +1 -0
  173. package/packages/pi/dist/shortcuts.js +231 -0
  174. package/packages/pi/dist/shortcuts.js.map +1 -0
  175. package/packages/pi/dist/startup-briefing.d.ts +13 -0
  176. package/packages/pi/dist/startup-briefing.d.ts.map +1 -0
  177. package/packages/pi/dist/startup-briefing.js +271 -0
  178. package/packages/pi/dist/startup-briefing.js.map +1 -0
  179. package/packages/pi/dist/stratus-bridge.d.ts +14 -0
  180. package/packages/pi/dist/stratus-bridge.d.ts.map +1 -0
  181. package/packages/pi/dist/stratus-bridge.js +104 -0
  182. package/packages/pi/dist/stratus-bridge.js.map +1 -0
  183. package/packages/pi/dist/subway-mesh.d.ts +88 -0
  184. package/packages/pi/dist/subway-mesh.d.ts.map +1 -0
  185. package/packages/pi/dist/subway-mesh.js +813 -0
  186. package/packages/pi/dist/subway-mesh.js.map +1 -0
  187. package/packages/pi/dist/synopsis-tool.d.ts +12 -0
  188. package/packages/pi/dist/synopsis-tool.d.ts.map +1 -0
  189. package/packages/pi/dist/synopsis-tool.js +84 -0
  190. package/packages/pi/dist/synopsis-tool.js.map +1 -0
  191. package/packages/pi/dist/tool-renderers.d.ts +55 -0
  192. package/packages/pi/dist/tool-renderers.d.ts.map +1 -0
  193. package/packages/pi/dist/tool-renderers.js +349 -0
  194. package/packages/pi/dist/tool-renderers.js.map +1 -0
  195. package/packages/pi/dist/training-buffer-tool.d.ts +16 -0
  196. package/packages/pi/dist/training-buffer-tool.d.ts.map +1 -0
  197. package/packages/pi/dist/training-buffer-tool.js +319 -0
  198. package/packages/pi/dist/training-buffer-tool.js.map +1 -0
  199. package/packages/pi/dist/types.d.ts +195 -0
  200. package/packages/pi/dist/types.d.ts.map +1 -0
  201. package/packages/pi/dist/types.js +11 -0
  202. package/packages/pi/dist/types.js.map +1 -0
  203. package/packages/pi/extensions/session.ts +115 -8
  204. package/packages/pi/extensions/training-buffer-tool.ts +15 -8
  205. package/packages/pi/extensions/types.ts +1 -0
  206. package/packages/pi/package.json +2 -3
@@ -583,6 +583,274 @@ async function runWithPR(projectRoot, task) {
583
583
  gitExec(["checkout", baseBranch], projectRoot);
584
584
  console.log(chalk.green(" PP: Done\n"));
585
585
  }
586
+ // ============================================================================
587
+ // Pickup — self-driving loop: poll backlog → pick → branch → execute → PR
588
+ // ============================================================================
589
+ function slugify(text) {
590
+ return text
591
+ .toLowerCase()
592
+ .replace(/[^a-z0-9]+/g, "-")
593
+ .replace(/^-+|-+$/g, "")
594
+ .slice(0, 40);
595
+ }
596
+ /**
597
+ * Extract cross-repo close reference from issue body metadata.
598
+ * Looks for patterns like "402goose/JFL-GTM#25" in the jfl metadata block,
599
+ * or falls back to same-repo #N.
600
+ */
601
+ function extractCloseRef(card) {
602
+ // Check for explicit cross-repo ref in metadata block
603
+ const metaMatch = card.description.match(/<!--\s*jfl:([\s\S]*?)-->/);
604
+ if (metaMatch) {
605
+ const meta = metaMatch[1];
606
+ const crossRepoMatch = meta.match(/close_ref:\s*(.+)/);
607
+ if (crossRepoMatch)
608
+ return crossRepoMatch[1].trim();
609
+ }
610
+ // Default: same-repo reference
611
+ return `#${card.number}`;
612
+ }
613
+ /**
614
+ * Append an entry to the pickup queue for audit/tracking.
615
+ */
616
+ function appendPickupQueue(projectRoot, entry) {
617
+ const queuePath = path.join(projectRoot, ".jfl", "pickup-queue.jsonl");
618
+ const dir = path.dirname(queuePath);
619
+ if (!fs.existsSync(dir))
620
+ fs.mkdirSync(dir, { recursive: true });
621
+ fs.appendFileSync(queuePath, JSON.stringify(entry) + "\n");
622
+ }
623
+ /**
624
+ * Poll jfl/backlog for source:linear issues, pick the highest priority,
625
+ * move to in_progress, create branch, execute, create PR, close on merge.
626
+ */
627
+ async function runPickup(projectRoot) {
628
+ console.log(chalk.bold("\n Peter Parker — Backlog Pickup\n"));
629
+ console.log(chalk.gray(" Polling jfl/backlog for source:linear issues...\n"));
630
+ if (!hasPi() && !hasRalphTui()) {
631
+ console.log(chalk.yellow(" Neither pi nor ralph-tui is installed"));
632
+ console.log(chalk.gray(" Install pi: npm i -g @mariozechner/pi-coding-agent"));
633
+ console.log(chalk.gray(" Or ralph-tui: bun install -g ralph-tui\n"));
634
+ return;
635
+ }
636
+ const { GitHubKanban } = await import("../lib/kanban-github.js");
637
+ let kb;
638
+ try {
639
+ kb = new GitHubKanban(projectRoot);
640
+ }
641
+ catch (err) {
642
+ console.log(chalk.red(` PP: ${err.message}`));
643
+ return;
644
+ }
645
+ // Fetch backlog cards with source:linear
646
+ let cards;
647
+ try {
648
+ cards = await kb.getCards({ column: "backlog", source: "linear" });
649
+ }
650
+ catch (err) {
651
+ console.log(chalk.red(` PP: Failed to fetch backlog: ${err.message}`));
652
+ return;
653
+ }
654
+ if (cards.length === 0) {
655
+ console.log(chalk.yellow(" No source:linear issues in jfl/backlog. Nothing to pick up.\n"));
656
+ return;
657
+ }
658
+ // Already sorted by priority desc from getCards
659
+ const card = cards[0];
660
+ console.log(chalk.cyan(` Picked: #${card.number} — ${card.title}`));
661
+ console.log(chalk.gray(` Priority: ${card.priority} Source: ${card.source}`));
662
+ if (card.labels.length > 0) {
663
+ console.log(chalk.gray(` Labels: ${card.labels.join(", ")}`));
664
+ }
665
+ console.log();
666
+ // Move to in_progress
667
+ try {
668
+ kb.pick(card.number, "peter-parker");
669
+ console.log(chalk.gray(` 📋 Issue #${card.number} → in_progress (assigned: peter-parker)`));
670
+ }
671
+ catch (err) {
672
+ console.log(chalk.yellow(` PP: Could not move issue: ${err.message}`));
673
+ // Continue anyway — don't block on label move failure
674
+ }
675
+ // Build task prompt from issue title + description
676
+ const taskLines = [`GitHub #${card.number}: ${card.title}`];
677
+ if (card.description) {
678
+ // Strip the jfl metadata block from the description for the prompt
679
+ const cleanDesc = card.description.replace(/<!--\s*jfl:[\s\S]*?-->/g, "").trim();
680
+ if (cleanDesc)
681
+ taskLines.push("", cleanDesc);
682
+ }
683
+ const task = taskLines.join("\n");
684
+ // Create branch
685
+ const baseBranch = "main";
686
+ const slug = slugify(card.title);
687
+ const branchName = `pp/issue-${card.number}-${slug}`;
688
+ console.log(chalk.cyan(`\n PP: Creating branch ${branchName}`));
689
+ gitExec(["fetch", "origin", baseBranch], projectRoot);
690
+ let checkout = gitExec(["checkout", "-b", branchName, `origin/${baseBranch}`], projectRoot);
691
+ if (!checkout.ok) {
692
+ checkout = gitExec(["checkout", "-b", branchName, baseBranch], projectRoot);
693
+ }
694
+ if (!checkout.ok) {
695
+ console.log(chalk.red(` PP: Failed to create branch ${branchName}`));
696
+ // Revert kanban move
697
+ try {
698
+ kb.move(card.number, "backlog");
699
+ }
700
+ catch { }
701
+ return;
702
+ }
703
+ // Track pickup
704
+ appendPickupQueue(projectRoot, {
705
+ ts: new Date().toISOString(),
706
+ issue: card.number,
707
+ title: card.title,
708
+ branch: branchName,
709
+ source: card.source,
710
+ priority: card.priority,
711
+ status: "in_progress",
712
+ });
713
+ // Run the agent
714
+ console.log(chalk.cyan(` PP: Running agent on task...\n`));
715
+ if (hasPi()) {
716
+ await runAgentWithPi(projectRoot, task);
717
+ }
718
+ else {
719
+ await runAgentWithRalphTui(projectRoot, task);
720
+ }
721
+ // Check for changes
722
+ const diffCheck = gitExec(["diff", "--quiet", "HEAD"], projectRoot);
723
+ const untrackedResult = spawnSync("git", ["ls-files", "--others", "--exclude-standard"], {
724
+ cwd: projectRoot,
725
+ encoding: "utf-8",
726
+ stdio: "pipe",
727
+ });
728
+ const untracked = (untrackedResult.stdout || "").trim();
729
+ if (diffCheck.ok && !untracked) {
730
+ console.log(chalk.yellow("\n PP: No changes made, reverting to backlog"));
731
+ gitExec(["checkout", baseBranch], projectRoot);
732
+ gitExec(["branch", "-D", branchName], projectRoot);
733
+ try {
734
+ kb.move(card.number, "backlog");
735
+ }
736
+ catch { }
737
+ appendPickupQueue(projectRoot, {
738
+ ts: new Date().toISOString(),
739
+ issue: card.number,
740
+ branch: branchName,
741
+ status: "no_changes",
742
+ });
743
+ return;
744
+ }
745
+ // Commit
746
+ console.log(chalk.cyan(" PP: Changes detected, committing..."));
747
+ const commitMsg = `fix(pp): #${card.number} ${card.title}`;
748
+ const commitHash = signedAgentCommit(projectRoot, commitMsg, {
749
+ agentId: "peter-parker",
750
+ sessionId: branchName,
751
+ });
752
+ if (!commitHash) {
753
+ console.log(chalk.red(" PP: Commit failed"));
754
+ gitExec(["checkout", baseBranch], projectRoot);
755
+ try {
756
+ kb.move(card.number, "backlog");
757
+ }
758
+ catch { }
759
+ return;
760
+ }
761
+ // Push
762
+ console.log(chalk.cyan(" PP: Pushing branch..."));
763
+ const pushResult = gitExec(["push", "-u", "origin", branchName], projectRoot);
764
+ if (!pushResult.ok) {
765
+ console.log(chalk.red(" PP: Push failed"));
766
+ console.log(chalk.gray(` ${pushResult.output}`));
767
+ gitExec(["checkout", baseBranch], projectRoot);
768
+ try {
769
+ kb.move(card.number, "backlog");
770
+ }
771
+ catch { }
772
+ return;
773
+ }
774
+ // Create PR
775
+ console.log(chalk.cyan(" PP: Creating PR..."));
776
+ const closeRef = extractCloseRef(card);
777
+ const prTitle = `PP: #${card.number} ${card.title.slice(0, 60)}`;
778
+ const prBody = [
779
+ "## Auto-generated by Peter Parker (Backlog Pickup)",
780
+ "",
781
+ `**Issue:** #${card.number} — ${card.title}`,
782
+ `**Branch:** \`${branchName}\``,
783
+ `**Source:** ${card.source}`,
784
+ "",
785
+ `Closes ${closeRef}`,
786
+ "",
787
+ "### Eval Suite",
788
+ "This PR will be evaluated by the CI eval suite.",
789
+ "Auto-merge will trigger if eval score improves over baseline.",
790
+ "",
791
+ "---",
792
+ "*Generated by JFL self-driving loop (pickup)*",
793
+ ].join("\n");
794
+ let prResult = ghExec([
795
+ "pr", "create",
796
+ "--title", prTitle,
797
+ "--body", prBody,
798
+ "--base", baseBranch,
799
+ "--head", branchName,
800
+ "--label", "pp-generated",
801
+ ], projectRoot);
802
+ if (!prResult.ok) {
803
+ prResult = ghExec([
804
+ "pr", "create",
805
+ "--title", prTitle,
806
+ "--body", prBody,
807
+ "--base", baseBranch,
808
+ "--head", branchName,
809
+ ], projectRoot);
810
+ }
811
+ if (!prResult.ok) {
812
+ console.log(chalk.red(" PP: Failed to create PR"));
813
+ console.log(chalk.gray(` ${prResult.output}`));
814
+ }
815
+ else {
816
+ const prUrl = prResult.output;
817
+ console.log(chalk.green(`\n PP: PR created at ${prUrl}`));
818
+ // Move to eval column
819
+ try {
820
+ kb.move(card.number, "eval");
821
+ }
822
+ catch { }
823
+ // Track completion
824
+ appendPickupQueue(projectRoot, {
825
+ ts: new Date().toISOString(),
826
+ issue: card.number,
827
+ branch: branchName,
828
+ pr_url: prUrl,
829
+ status: "pr_created",
830
+ });
831
+ await postHubEvent(projectRoot, "peter:pickup-complete", {
832
+ issue: card.number,
833
+ title: card.title,
834
+ branch: branchName,
835
+ pr_url: prUrl,
836
+ source: card.source,
837
+ });
838
+ }
839
+ // Write journal entry
840
+ writeJournalEntry(projectRoot, {
841
+ v: 1,
842
+ ts: new Date().toISOString(),
843
+ session: branchName,
844
+ type: "feature",
845
+ status: "complete",
846
+ title: `Pickup: #${card.number} ${card.title}`,
847
+ summary: `Auto-picked source:linear issue from backlog and executed. Branch: ${branchName}`,
848
+ detail: `Issue: #${card.number} — ${card.title}\nSource: ${card.source}\nPriority: ${card.priority}`,
849
+ agent_id: "peter-parker",
850
+ });
851
+ gitExec(["checkout", baseBranch], projectRoot);
852
+ console.log(chalk.green(" PP: Pickup complete.\n"));
853
+ }
586
854
  function buildRLState(evals, trajectoryLength, recentDeltas) {
587
855
  const latest = evals.sort((a, b) => b.ts.localeCompare(a.ts))[0];
588
856
  return {
@@ -2265,12 +2533,17 @@ export async function peterCommand(action, options = {}) {
2265
2533
  await runReview(projectRoot);
2266
2534
  break;
2267
2535
  }
2536
+ case "pickup": {
2537
+ await runPickup(projectRoot);
2538
+ break;
2539
+ }
2268
2540
  default: {
2269
2541
  console.log(chalk.bold("\n Peter Parker - Model-Routed Agent Orchestrator\n"));
2270
2542
  console.log(chalk.gray(" Commands:"));
2271
2543
  console.log(" jfl peter setup [--cost|--balanced|--quality] Generate agent config");
2272
2544
  console.log(" jfl peter run [--task <task>] Run orchestrator");
2273
2545
  console.log(" jfl peter pr --task <task> Run + branch + PR");
2546
+ console.log(" jfl peter pickup Poll backlog, pick source:linear issue, execute, PR");
2274
2547
  console.log(" jfl peter experiment Proactive: pick + execute next experiment");
2275
2548
  console.log(" jfl peter autoresearch [--rounds N] [--budget $] [--pi]");
2276
2549
  console.log(" Autoresearch mode with Pi runtime");