jfl 0.9.1 → 0.9.3

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 (126) hide show
  1. package/dist/commands/context-hub.d.ts.map +1 -1
  2. package/dist/commands/context-hub.js +141 -3
  3. package/dist/commands/context-hub.js.map +1 -1
  4. package/dist/commands/ide.d.ts.map +1 -1
  5. package/dist/commands/ide.js +22 -0
  6. package/dist/commands/ide.js.map +1 -1
  7. package/dist/commands/init.d.ts.map +1 -1
  8. package/dist/commands/init.js +6 -0
  9. package/dist/commands/init.js.map +1 -1
  10. package/dist/commands/linear.d.ts.map +1 -1
  11. package/dist/commands/linear.js +24 -0
  12. package/dist/commands/linear.js.map +1 -1
  13. package/dist/commands/peter.d.ts.map +1 -1
  14. package/dist/commands/peter.js +11 -15
  15. package/dist/commands/peter.js.map +1 -1
  16. package/dist/commands/pi.d.ts +3 -0
  17. package/dist/commands/pi.d.ts.map +1 -1
  18. package/dist/commands/pi.js +19 -0
  19. package/dist/commands/pi.js.map +1 -1
  20. package/dist/commands/pivot.d.ts.map +1 -1
  21. package/dist/commands/pivot.js +22 -25
  22. package/dist/commands/pivot.js.map +1 -1
  23. package/dist/commands/repair.d.ts.map +1 -1
  24. package/dist/commands/repair.js +26 -0
  25. package/dist/commands/repair.js.map +1 -1
  26. package/dist/commands/session.d.ts.map +1 -1
  27. package/dist/commands/session.js +39 -0
  28. package/dist/commands/session.js.map +1 -1
  29. package/dist/commands/start.d.ts.map +1 -1
  30. package/dist/commands/start.js +60 -0
  31. package/dist/commands/start.js.map +1 -1
  32. package/dist/commands/update.d.ts.map +1 -1
  33. package/dist/commands/update.js +3 -1
  34. package/dist/commands/update.js.map +1 -1
  35. package/dist/index.js +3 -0
  36. package/dist/index.js.map +1 -1
  37. package/dist/lib/advanced-setup.js +7 -7
  38. package/dist/lib/advanced-setup.js.map +1 -1
  39. package/dist/lib/agent-session.d.ts.map +1 -1
  40. package/dist/lib/agent-session.js +6 -3
  41. package/dist/lib/agent-session.js.map +1 -1
  42. package/dist/lib/discovery-agent.js +1 -1
  43. package/dist/lib/discovery-agent.js.map +1 -1
  44. package/dist/lib/gtm-generator.js +7 -0
  45. package/dist/lib/gtm-generator.js.map +1 -1
  46. package/dist/lib/linear-webhook.d.ts +50 -0
  47. package/dist/lib/linear-webhook.d.ts.map +1 -0
  48. package/dist/lib/linear-webhook.js +92 -0
  49. package/dist/lib/linear-webhook.js.map +1 -0
  50. package/dist/lib/memory-db.d.ts +8 -0
  51. package/dist/lib/memory-db.d.ts.map +1 -1
  52. package/dist/lib/memory-db.js +24 -0
  53. package/dist/lib/memory-db.js.map +1 -1
  54. package/dist/lib/memory-indexer.d.ts +8 -0
  55. package/dist/lib/memory-indexer.d.ts.map +1 -1
  56. package/dist/lib/memory-indexer.js +30 -1
  57. package/dist/lib/memory-indexer.js.map +1 -1
  58. package/dist/lib/memory-search.d.ts.map +1 -1
  59. package/dist/lib/memory-search.js +2 -7
  60. package/dist/lib/memory-search.js.map +1 -1
  61. package/dist/lib/onboarding.js +1 -1
  62. package/dist/lib/onboarding.js.map +1 -1
  63. package/dist/lib/rl-manager.d.ts +1 -1
  64. package/dist/lib/rl-manager.d.ts.map +1 -1
  65. package/dist/lib/rl-manager.js +3 -3
  66. package/dist/lib/rl-manager.js.map +1 -1
  67. package/dist/lib/service-detector.js +2 -2
  68. package/dist/lib/service-detector.js.map +1 -1
  69. package/dist/lib/telemetry/physical-world-collector.js +1 -1
  70. package/dist/lib/telemetry/physical-world-collector.js.map +1 -1
  71. package/dist/lib/tool-schemas.d.ts +35 -0
  72. package/dist/lib/tool-schemas.d.ts.map +1 -0
  73. package/dist/lib/tool-schemas.js +246 -0
  74. package/dist/lib/tool-schemas.js.map +1 -0
  75. package/dist/lib/workspace/data-pipeline.d.ts.map +1 -1
  76. package/dist/lib/workspace/data-pipeline.js +29 -20
  77. package/dist/lib/workspace/data-pipeline.js.map +1 -1
  78. package/dist/lib/workspace/engine.d.ts +1 -0
  79. package/dist/lib/workspace/engine.d.ts.map +1 -1
  80. package/dist/lib/workspace/engine.js +10 -0
  81. package/dist/lib/workspace/engine.js.map +1 -1
  82. package/dist/mcp/context-hub-mcp.js +7 -1
  83. package/dist/mcp/context-hub-mcp.js.map +1 -1
  84. package/dist/types/telemetry.d.ts +1 -0
  85. package/dist/types/telemetry.d.ts.map +1 -1
  86. package/dist/utils/git.d.ts +1 -1
  87. package/dist/utils/git.d.ts.map +1 -1
  88. package/dist/utils/git.js +9 -6
  89. package/dist/utils/git.js.map +1 -1
  90. package/dist/utils/provenance.d.ts +65 -0
  91. package/dist/utils/provenance.d.ts.map +1 -0
  92. package/dist/utils/provenance.js +213 -0
  93. package/dist/utils/provenance.js.map +1 -0
  94. package/package.json +1 -1
  95. package/packages/pi/assets/boot.mp3 +0 -0
  96. package/packages/pi/extensions/autoresearch.ts +3 -2
  97. package/packages/pi/extensions/context.ts +38 -114
  98. package/packages/pi/extensions/eval.ts +2 -1
  99. package/packages/pi/extensions/header.ts +171 -0
  100. package/packages/pi/extensions/hub-tools.ts +31 -11
  101. package/packages/pi/extensions/hud-tool.ts +231 -70
  102. package/packages/pi/extensions/index.ts +65 -64
  103. package/packages/pi/extensions/jfl-resolve.ts +98 -0
  104. package/packages/pi/extensions/journal.ts +91 -6
  105. package/packages/pi/extensions/map-bridge.ts +31 -0
  106. package/packages/pi/extensions/memory-tool.ts +3 -3
  107. package/packages/pi/extensions/onboarding-v2.ts +263 -410
  108. package/packages/pi/extensions/onboarding-v3.ts +32 -21
  109. package/packages/pi/extensions/peter-parker.ts +2 -1
  110. package/packages/pi/extensions/policy-head-tool.ts +3 -2
  111. package/packages/pi/extensions/portfolio-bridge.ts +3 -4
  112. package/packages/pi/extensions/service-skills.ts +6 -1
  113. package/packages/pi/extensions/session.ts +97 -15
  114. package/packages/pi/extensions/startup-briefing.ts +313 -0
  115. package/packages/pi/extensions/stratus-bridge.ts +2 -1
  116. package/packages/pi/extensions/subway-mesh.ts +893 -0
  117. package/packages/pi/extensions/synopsis-tool.ts +6 -1
  118. package/packages/pi/extensions/training-buffer-tool.ts +3 -2
  119. package/packages/pi/extensions/types.ts +3 -0
  120. package/packages/pi/package.json +4 -1
  121. package/packages/pi/skills/viz/SKILL.md +204 -0
  122. package/scripts/pp-branch-pr.sh +24 -6
  123. package/scripts/pp-branch-pr.sh.bak +115 -0
  124. package/template/.pi/settings.json +5 -0
  125. package/template/CLAUDE.md +82 -1738
  126. package/template/CLAUDE.md.bak +0 -1187
@@ -48,7 +48,12 @@ export function setupSynopsisTool(ctx: PiContext): void {
48
48
  },
49
49
  },
50
50
  async handler(input) {
51
- const { hours, author } = input as { hours?: number; author?: string }
51
+ const raw = input as { hours?: number | string; author?: string }
52
+ // Model sometimes passes "24h" or "48h" — strip the 'h' and parse
53
+ const hours = typeof raw.hours === "string"
54
+ ? parseInt(String(raw.hours).replace(/[^0-9]/g, ""), 10) || 24
55
+ : raw.hours
56
+ const author = raw.author
52
57
 
53
58
  const synopsisScript = findSynopsisScript(projectRoot)
54
59
  if (synopsisScript) {
@@ -14,6 +14,7 @@
14
14
  import { existsSync, readFileSync } from "fs"
15
15
  import { join } from "path"
16
16
  import type { PiContext, JflConfig, AgentEndEvent } from "./types.js"
17
+ import { jflImport } from "./jfl-resolve.js"
17
18
  import { emitCustomEvent } from "./map-bridge.js"
18
19
 
19
20
  let projectRoot = ""
@@ -21,7 +22,7 @@ let projectRoot = ""
21
22
  async function getTrainingBuffer(): Promise<any> {
22
23
  try {
23
24
  // @ts-ignore — resolved from jfl package at runtime
24
- const { TrainingBuffer } = await import("../../src/lib/training-buffer.js")
25
+ const { TrainingBuffer } = await jflImport("training-buffer")
25
26
  return new TrainingBuffer(projectRoot)
26
27
  } catch {
27
28
  return null
@@ -31,7 +32,7 @@ async function getTrainingBuffer(): Promise<any> {
31
32
  async function getTupleMiner(): Promise<any> {
32
33
  try {
33
34
  // @ts-ignore — resolved from jfl package at runtime
34
- return await import("../../src/lib/tuple-miner.js")
35
+ return await jflImport("tuple-miner")
35
36
  } catch {
36
37
  return null
37
38
  }
@@ -74,6 +74,7 @@ export interface PiContext {
74
74
  setWidget(id: string, content: string[] | WidgetFactory | undefined, opts?: { placement?: "aboveEditor" | "belowEditor" }): void
75
75
  setStatus(key: string, text: string | undefined): void
76
76
  setFooter(factory: ((tui: any, theme: PiTheme, footerData: any) => any) | undefined): void
77
+ setHeader?(factory: ((tui: any, theme: PiTheme) => { render: (width: number) => string[]; invalidate: () => void }) | undefined): void
77
78
  setEditorText(text: string): void
78
79
  theme: PiTheme
79
80
  hasUI: boolean
@@ -115,6 +116,8 @@ export interface AgentEndEvent {
115
116
  export interface ToolExecutionEvent {
116
117
  toolName?: string
117
118
  tool?: string
119
+ input?: Record<string, any>
120
+ args?: Record<string, any>
118
121
  result?: unknown
119
122
  isError?: boolean
120
123
  duration?: number
@@ -29,6 +29,7 @@
29
29
  ],
30
30
  "dependencies": {
31
31
  "axios": "^1.13.4",
32
+ "ws": "^8.19.0",
32
33
  "yaml": "^2.8.2"
33
34
  },
34
35
  "devDependencies": {
@@ -36,7 +37,9 @@
36
37
  "typescript": "^5.3.3"
37
38
  },
38
39
  "pi": {
39
- "entry": "dist/extensions/index.js",
40
+
41
+ "entry": "dist/index.js",
42
+ "extensions": ["dist/index.js"],
40
43
  "skills": "skills",
41
44
  "themes": "themes/jfl.theme.json",
42
45
  "teams": "teams"
@@ -0,0 +1,204 @@
1
+ ---
2
+ name: viz
3
+ description: Terminal data visualization via kuva — inline plots for agents and humans
4
+ ---
5
+
6
+ # /viz — Terminal Visualization
7
+
8
+ Pipe JFL data to kuva for inline terminal plots. Agents see results without leaving flow.
9
+
10
+ ## Prerequisites
11
+
12
+ ```bash
13
+ cargo install kuva --features cli
14
+ ```
15
+
16
+ If kuva is not installed, falls back to ASCII bar/sparkline rendering.
17
+
18
+ ## Commands
19
+
20
+ ```
21
+ /viz events # Event bus activity (bar chart by type, sankey of service flows)
22
+ /viz sessions # Session activity (line chart over time, duration box plot)
23
+ /viz costs # API costs (bar by model, pie by provider)
24
+ /viz tools # Tool usage frequency (bar chart)
25
+ /viz flows # Flow trigger rates (bar chart, sankey of trigger→action)
26
+ /viz arena # Arena leaderboard (composite bar chart, score trajectory)
27
+ /viz learning # Pattern confidence trends (line chart)
28
+ /viz health # Service health dashboard (cost sparklines, error bars, latency box)
29
+ /viz <custom> # Describe what you want to visualize
30
+ ```
31
+
32
+ ## How It Works
33
+
34
+ Each `/viz` command:
35
+ 1. Reads the relevant data source (events, journals, telemetry, arena results)
36
+ 2. Transforms to TSV format
37
+ 3. Pipes to `kuva [plot-type] --terminal`
38
+ 4. Renders inline in the terminal
39
+
40
+ ## Implementation
41
+
42
+ ### /viz events
43
+
44
+ Read `.jfl/service-events.jsonl` and `.jfl/map-events.jsonl`:
45
+
46
+ ```bash
47
+ # Event type distribution
48
+ cat .jfl/service-events.jsonl | \
49
+ jq -r '.type' | sort | uniq -c | sort -rn | \
50
+ awk '{print $2"\t"$1}' | \
51
+ kuva bar --label-col 0 --value-col 1 --title "Events by Type" --terminal
52
+
53
+ # Service-to-service flow (sankey)
54
+ cat .jfl/service-events.jsonl | \
55
+ jq -r '[.source // "unknown", .type, 1] | @tsv' | \
56
+ kuva sankey --source-col 0 --target-col 1 --value-col 2 --title "Event Flows" --terminal
57
+ ```
58
+
59
+ Or use the programmatic API from `jfl-cli/src/lib/kuva.ts`:
60
+
61
+ ```typescript
62
+ import { barChart, linePlot, sparkline } from 'jfl-cli/src/lib/kuva.js'
63
+
64
+ const events = loadEvents()
65
+ const byType = countBy(events, 'type')
66
+ const chart = barChart(
67
+ Object.entries(byType).map(([label, value]) => ({ label, value })),
68
+ 'Events by Type'
69
+ )
70
+ console.log(chart)
71
+ ```
72
+
73
+ ### /viz sessions
74
+
75
+ ```bash
76
+ # Sessions over time (line)
77
+ cat .jfl/journal/*.jsonl | \
78
+ jq -r 'select(.type == "session-end") | [.ts[:10], 1] | @tsv' | \
79
+ sort | uniq -c | awk '{print $2"\t"$1}' | \
80
+ kuva line --x 0 --y 1 --title "Sessions per Day" --terminal
81
+ ```
82
+
83
+ ### /viz costs
84
+
85
+ ```bash
86
+ # Cost by model (bar)
87
+ cat .jfl/telemetry-queue.jsonl | \
88
+ jq -r 'select(.event == "stratus:api_call") | [(.model_name // "unknown"), .estimated_cost_usd] | @tsv' | \
89
+ kuva bar --label-col 0 --value-col 1 --title "Cost by Model" --terminal
90
+ ```
91
+
92
+ ### /viz arena
93
+
94
+ ```bash
95
+ # Run from arena directory
96
+ cd /path/to/productrank-arena
97
+ npm run arena -- leaderboard --all --plots
98
+ ```
99
+
100
+ Or programmatically — arena's `formatLeaderboardPlots()` renders composite scores as kuva bar chart.
101
+
102
+ ### /viz flows
103
+
104
+ ```bash
105
+ # Flow triggers (bar)
106
+ cat .jfl/service-events.jsonl | \
107
+ jq -r 'select(.type == "flow:triggered") | .data.flow_name' | \
108
+ sort | uniq -c | sort -rn | awk '{print $2"\t"$1}' | \
109
+ kuva bar --label-col 0 --value-col 1 --title "Flow Triggers" --terminal
110
+
111
+ # Flow trigger→action sankey
112
+ cat .jfl/service-events.jsonl | \
113
+ jq -r 'select(.type == "flow:completed") | [.data.flow_name, .data.action_type, 1] | @tsv' | \
114
+ kuva sankey --source-col 0 --target-col 1 --value-col 2 --title "Flow Actions" --terminal
115
+ ```
116
+
117
+ ### /viz health
118
+
119
+ Composite dashboard — renders multiple charts:
120
+
121
+ ```
122
+ Health Dashboard
123
+ ━━━━━━━━━━━━━━━━
124
+
125
+ API Costs (last 24h)
126
+ [kuva bar: cost by model]
127
+
128
+ Error Rate ▁▂▁▁▃▅▂▁▁▁ (sparkline)
129
+
130
+ Latency Distribution
131
+ [kuva box: latency by endpoint]
132
+
133
+ Session Duration
134
+ [kuva box: duration by session]
135
+ ```
136
+
137
+ ### /viz learning (RL / Training)
138
+
139
+ For agents with reinforcement learning loops:
140
+
141
+ ```typescript
142
+ // After each training epoch
143
+ const rewards = epochs.map((e, i) => ({ ts: `epoch-${i}`, value: e.reward }))
144
+ const chart = linePlot(rewards, 'Reward per Epoch')
145
+ console.log(chart)
146
+
147
+ // Action distribution
148
+ const actions = countBy(episodes, 'action')
149
+ const actionChart = barChart(
150
+ Object.entries(actions).map(([label, value]) => ({ label, value })),
151
+ 'Action Frequency'
152
+ )
153
+ console.log(actionChart)
154
+ ```
155
+
156
+ ### /viz custom
157
+
158
+ When user describes what they want to visualize, the agent:
159
+ 1. Identifies the data source
160
+ 2. Extracts/transforms to TSV
161
+ 3. Picks the right kuva plot type
162
+ 4. Renders with `--terminal`
163
+
164
+ ## Available Plot Types
165
+
166
+ | kuva command | Best for | Key flags |
167
+ |-------------|----------|-----------|
168
+ | `bar` | Categorical comparisons | `--label-col`, `--value-col` |
169
+ | `line` | Time series, trends | `--x`, `--y`, `--color-by` |
170
+ | `scatter` | Correlations, clustering | `--x`, `--y`, `--color-by` |
171
+ | `box` | Distributions, outliers | `--group-col`, `--value-col` |
172
+ | `histogram` | Value distributions | `--value-col`, `--bins` |
173
+ | `pie` | Proportions | `--label-col`, `--value-col`, `--donut` |
174
+ | `sankey` | Flow routing, transitions | `--source-col`, `--target-col`, `--value-col` |
175
+ | `heatmap` | Matrix data, correlations | First col = row labels |
176
+ | `violin` | Distribution shape | `--group-col`, `--value-col` |
177
+
178
+ ## Design Principles
179
+
180
+ 1. **TSV is the universal interface** — any data source that can produce rows can generate kuva plots
181
+ 2. **Graceful degradation** — ASCII fallback (bars, sparklines) when kuva isn't installed
182
+ 3. **Agent-native** — inline terminal output, no browser needed, no context-switching
183
+ 4. **Composable** — pipe any JSONL through `jq -r @tsv` into kuva. Unix philosophy.
184
+ 5. **Zero coupling** — kuva is a standalone Rust binary. kuva.ts is a standalone module. Neither needs the other's internals.
185
+
186
+ ## Examples
187
+
188
+ ```
189
+ User: "show me event activity"
190
+ Agent: *runs /viz events*
191
+ → Bar chart of event types + sankey of service flows
192
+
193
+ User: "what's our cost breakdown?"
194
+ Agent: *runs /viz costs*
195
+ → Bar chart by model + pie chart by provider
196
+
197
+ User: "how is the arena looking?"
198
+ Agent: *runs /viz arena*
199
+ → Leaderboard table + composite score bar chart
200
+
201
+ User: "plot my training rewards"
202
+ Agent: *runs /viz learning with user's data*
203
+ → Line chart of reward per epoch + action frequency bars
204
+ ```
@@ -43,15 +43,33 @@ if git diff --quiet HEAD && [ -z "$(git ls-files --others --exclude-standard)" ]
43
43
  exit 0
44
44
  fi
45
45
 
46
- # 4. Commit
46
+ # 4. Commit with provenance signing
47
47
  git add -A
48
- COMMIT_MSG="fix(pp): ${TASK}
49
48
 
50
- Agent: peter-parker
51
- Branch: ${BRANCH_NAME}
52
- Auto-generated by JFL self-driving loop
49
+ AGENT_ID="peter-parker"
50
+ AGENT_SESSION="${BRANCH_NAME}"
51
+ AGENT_TIMESTAMP="$(date -u +"%Y-%m-%dT%H:%M:%SZ")"
52
+
53
+ # Compute provenance hash from staged diff + agent identity
54
+ PROVENANCE_KEY_PATH=".jfl/provenance-key"
55
+ if [ ! -f "${PROVENANCE_KEY_PATH}" ]; then
56
+ mkdir -p .jfl
57
+ openssl rand -hex 32 > "${PROVENANCE_KEY_PATH}"
58
+ chmod 600 "${PROVENANCE_KEY_PATH}"
59
+ fi
60
+ PROVENANCE_KEY=$(cat "${PROVENANCE_KEY_PATH}")
61
+ STAGED_DIFF=$(git diff --cached)
62
+ PROVENANCE_PAYLOAD="${AGENT_ID}
63
+ ${AGENT_TIMESTAMP}
64
+ ${STAGED_DIFF}"
65
+ PROVENANCE_HASH="sha256:$(printf '%s' "${PROVENANCE_PAYLOAD}" | openssl dgst -sha256 -hmac "${PROVENANCE_KEY}" | awk '{print $NF}')"
66
+
67
+ COMMIT_MSG="fix(pp): ${TASK}
53
68
 
54
- Co-authored-by: Peter Parker <pp@jfl.dev>"
69
+ Agent-Id: ${AGENT_ID}
70
+ Agent-Session: ${AGENT_SESSION}
71
+ Provenance-Hash: ${PROVENANCE_HASH}
72
+ Agent-Timestamp: ${AGENT_TIMESTAMP}"
55
73
 
56
74
  git commit -m "${COMMIT_MSG}"
57
75
 
@@ -0,0 +1,115 @@
1
+ #!/bin/bash
2
+ # scripts/pp-branch-pr.sh
3
+ #
4
+ # Wraps Peter Parker agent execution in git branch + PR workflow.
5
+ # Creates a branch, runs the agent, commits changes, opens a PR,
6
+ # and posts a pr:created event to the hub.
7
+ #
8
+ # Called by flow engine spawn action or directly.
9
+ #
10
+ # Usage: pp-branch-pr.sh <task-description> [hub-url] [hub-token]
11
+
12
+ set -euo pipefail
13
+
14
+ TASK="${1:?Usage: pp-branch-pr.sh <task-description> [hub-url] [hub-token]}"
15
+ HUB_URL="${2:-}"
16
+ HUB_TOKEN="${3:-}"
17
+ BRANCH_NAME="pp/fix-$(date +%s)"
18
+ BASE_BRANCH="main"
19
+
20
+ if [ -z "$HUB_URL" ] && [ -f ".jfl/context-hub.port" ]; then
21
+ PORT=$(cat .jfl/context-hub.port)
22
+ HUB_URL="http://localhost:${PORT}"
23
+ fi
24
+ if [ -z "$HUB_TOKEN" ] && [ -f ".jfl/context-hub.token" ]; then
25
+ HUB_TOKEN=$(cat .jfl/context-hub.token)
26
+ fi
27
+
28
+ echo "PP: Creating branch ${BRANCH_NAME}"
29
+
30
+ # 1. Create branch from clean main
31
+ git fetch origin "${BASE_BRANCH}" 2>/dev/null || true
32
+ git checkout -b "${BRANCH_NAME}" "origin/${BASE_BRANCH}" 2>/dev/null || git checkout -b "${BRANCH_NAME}" "${BASE_BRANCH}"
33
+
34
+ # 2. Run Peter Parker
35
+ echo "PP: Running agent on task: ${TASK}"
36
+ jfl peter run --task "${TASK}"
37
+
38
+ # 3. Check if anything changed
39
+ if git diff --quiet HEAD && [ -z "$(git ls-files --others --exclude-standard)" ]; then
40
+ echo "PP: No changes made, cleaning up"
41
+ git checkout "${BASE_BRANCH}" 2>/dev/null || true
42
+ git branch -D "${BRANCH_NAME}" 2>/dev/null || true
43
+ exit 0
44
+ fi
45
+
46
+ # 4. Commit
47
+ git add -A
48
+ COMMIT_MSG="fix(pp): ${TASK}
49
+
50
+ Agent: peter-parker
51
+ Branch: ${BRANCH_NAME}
52
+ Auto-generated by JFL self-driving loop
53
+
54
+ Co-authored-by: Peter Parker <pp@jfl.dev>"
55
+
56
+ git commit -m "${COMMIT_MSG}"
57
+
58
+ # 5. Push
59
+ git push -u origin "${BRANCH_NAME}"
60
+
61
+ # 6. Create PR
62
+ PR_TITLE="PP: $(echo "${TASK}" | head -c 60)"
63
+ PR_BODY="## Auto-generated by Peter Parker
64
+
65
+ **Task:** ${TASK}
66
+ **Branch:** \`${BRANCH_NAME}\`
67
+
68
+ ### Eval Suite
69
+ This PR will be evaluated by the CI eval suite.
70
+ Auto-merge will trigger if eval score improves over baseline.
71
+
72
+ ---
73
+ *Generated by JFL self-driving loop*"
74
+
75
+ PR_URL=$(gh pr create \
76
+ --title "${PR_TITLE}" \
77
+ --body "${PR_BODY}" \
78
+ --base "${BASE_BRANCH}" \
79
+ --head "${BRANCH_NAME}" \
80
+ --label "pp-generated" 2>&1) || {
81
+ echo "PP: Label may not exist, retrying without label"
82
+ PR_URL=$(gh pr create \
83
+ --title "${PR_TITLE}" \
84
+ --body "${PR_BODY}" \
85
+ --base "${BASE_BRANCH}" \
86
+ --head "${BRANCH_NAME}" 2>&1)
87
+ }
88
+
89
+ echo "PP: PR created at ${PR_URL}"
90
+
91
+ # 7. Post event to hub
92
+ if [ -n "${HUB_URL}" ]; then
93
+ TASK_JSON=$(printf '%s' "${TASK}" | python3 -c 'import sys,json; print(json.dumps(sys.stdin.read().strip()))')
94
+
95
+ CURL_ARGS=(-s -X POST "${HUB_URL}/api/events" -H "Content-Type: application/json")
96
+ if [ -n "${HUB_TOKEN}" ]; then
97
+ CURL_ARGS+=(-H "Authorization: Bearer ${HUB_TOKEN}")
98
+ fi
99
+ CURL_ARGS+=(-d "{
100
+ \"type\": \"pr:created\",
101
+ \"source\": \"peter-parker\",
102
+ \"data\": {
103
+ \"task\": ${TASK_JSON},
104
+ \"pr_url\": \"${PR_URL}\",
105
+ \"branch\": \"${BRANCH_NAME}\"
106
+ }
107
+ }")
108
+
109
+ curl "${CURL_ARGS[@]}" 2>/dev/null || echo "PP: Warning - could not post event to hub"
110
+ fi
111
+
112
+ # 8. Return to base branch
113
+ git checkout "${BASE_BRANCH}" 2>/dev/null || true
114
+
115
+ echo "PP: Done"
@@ -0,0 +1,5 @@
1
+ {
2
+ "packages": [
3
+ "npm:@jfl/pi"
4
+ ]
5
+ }