@sebastianandreasson/pi-autonomous-agents 0.1.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/README.md +102 -0
- package/SETUP.md +171 -0
- package/docs/PI_SUPERVISOR.md +246 -0
- package/package.json +37 -0
- package/pi.config.json +28 -0
- package/src/cli.mjs +48 -0
- package/src/index.mjs +7 -0
- package/src/pi-client.mjs +195 -0
- package/src/pi-config.mjs +296 -0
- package/src/pi-flow.mjs +42 -0
- package/src/pi-heartbeat.mjs +152 -0
- package/src/pi-prompts.mjs +274 -0
- package/src/pi-repo.mjs +496 -0
- package/src/pi-report.mjs +55 -0
- package/src/pi-rpc-adapter.mjs +531 -0
- package/src/pi-supervisor.mjs +1156 -0
- package/src/pi-telemetry.mjs +63 -0
- package/src/pi-visual-once.mjs +86 -0
- package/src/pi-visual-review.mjs +236 -0
- package/templates/DEVELOPER.md +34 -0
- package/templates/PROJECT_SETUP.md +42 -0
- package/templates/TESTER.md +37 -0
- package/templates/gitignore.fragment +11 -0
- package/templates/pi.config.example.json +53 -0
|
@@ -0,0 +1,274 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
|
|
3
|
+
function shortName(filePath) {
|
|
4
|
+
return path.basename(filePath)
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
function formatVisualFeedback(visualFeedback) {
|
|
8
|
+
const text = String(visualFeedback ?? '').trim()
|
|
9
|
+
if (text === '') {
|
|
10
|
+
return ''
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
return `\nLatest visual feedback from prior runs:\n${text}\n`
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function formatTesterFeedback(testerFeedback) {
|
|
17
|
+
const text = String(testerFeedback ?? '').trim()
|
|
18
|
+
if (text === '') {
|
|
19
|
+
return ''
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
return `\nLatest tester feedback from prior runs:\n${text}\n`
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function indentBlock(text, prefix = '') {
|
|
26
|
+
return String(text)
|
|
27
|
+
.split('\n')
|
|
28
|
+
.map((line) => `${prefix}${line}`)
|
|
29
|
+
.join('\n')
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function innerLoopValidationRules(verificationCommand) {
|
|
33
|
+
const command = String(verificationCommand ?? '').trim() || 'the configured smoke verification command'
|
|
34
|
+
return [
|
|
35
|
+
`- Use ${command} as the fast inner-loop gate. Do not substitute a long real-time full-flow spec unless the task explicitly requires it.`,
|
|
36
|
+
'- If a long Playwright happy-path spec changes, validate with smoke plus one narrow targeted spec or deterministic state hook, not the entire full-flow run.',
|
|
37
|
+
'- Reserve long full-flow Playwright specs for an explicit nightly or post-run lane, not the developer turn.',
|
|
38
|
+
].join('\n')
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function staleEditRecoveryRules() {
|
|
42
|
+
return [
|
|
43
|
+
'- After one failed edit attempt, reread the file before trying again.',
|
|
44
|
+
'- Do not repeat the same exact oldText-based edit on the same file.',
|
|
45
|
+
].join('\n')
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
export function buildMainPrompt(config, options = {}) {
|
|
49
|
+
const taskFile = shortName(config.taskFile)
|
|
50
|
+
const instructionsFile = shortName(config.developerInstructionsFile)
|
|
51
|
+
const visualFeedbackSection = formatVisualFeedback(options.visualFeedback)
|
|
52
|
+
const testerFeedbackSection = formatTesterFeedback(options.testerFeedback)
|
|
53
|
+
|
|
54
|
+
return `Read ${taskFile} and ${instructionsFile}.
|
|
55
|
+
${visualFeedbackSection}
|
|
56
|
+
${testerFeedbackSection}
|
|
57
|
+
|
|
58
|
+
Work only on the current phase.
|
|
59
|
+
Select the first unchecked actionable checkbox in phase order.
|
|
60
|
+
Complete that task, or at most 2 tightly related unchecked tasks if they are naturally done together.
|
|
61
|
+
|
|
62
|
+
Rules:
|
|
63
|
+
- Start by checking git status so you know whether unrelated changes already exist.
|
|
64
|
+
- Update code, config, and docs only as needed for the selected task.
|
|
65
|
+
- Tick only the checkbox items that are actually completed.
|
|
66
|
+
- Do not select "Done when" checkboxes as the active task unless the implementation items in that section are already satisfied.
|
|
67
|
+
- If you discover missing prerequisite work, add a new unchecked checkbox under the same phase, then complete only what is necessary.
|
|
68
|
+
- Do not skip to a later phase unless the current task is blocked.
|
|
69
|
+
- If blocked, add a brief note directly under the relevant task in ${taskFile} explaining the blocker, then stop.
|
|
70
|
+
- Do not create GitHub issue templates, project-management files, or unrelated scaffolding.
|
|
71
|
+
- Do not edit lockfiles, generated files, or unrelated assets.
|
|
72
|
+
- If dependencies must change, edit package.json only, then stop.
|
|
73
|
+
- Prefer the smallest viable implementation that fully satisfies the selected checkbox.
|
|
74
|
+
- Avoid broad refactors unless the selected task explicitly requires them.
|
|
75
|
+
${indentBlock(innerLoopValidationRules(config.testCommand), '\t')}
|
|
76
|
+
- Trust tool results over your own guesses. If a read tool shows file contents, use that exact output instead of arguing with it.
|
|
77
|
+
- Do not repeatedly rewrite the same file because you suspect a formatting issue. Read once, identify the exact mismatch, then make one focused fix.
|
|
78
|
+
${indentBlock(staleEditRecoveryRules(), '\t')}
|
|
79
|
+
- Do not create the final commit during the developer pass. Leave a clean diff for the tester to validate and commit if it passes.
|
|
80
|
+
|
|
81
|
+
Before stopping:
|
|
82
|
+
- Tick completed checkbox items in ${taskFile}.
|
|
83
|
+
- Keep changes scoped to one coherent step.
|
|
84
|
+
- Stop after finishing that step.`
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
export function buildFixPrompt(config, recentVerificationOutput, options = {}) {
|
|
88
|
+
const taskFile = shortName(config.taskFile)
|
|
89
|
+
const instructionsFile = shortName(config.developerInstructionsFile)
|
|
90
|
+
const visualFeedbackSection = formatVisualFeedback(options.visualFeedback)
|
|
91
|
+
const testerFeedbackSection = formatTesterFeedback(options.testerFeedback)
|
|
92
|
+
|
|
93
|
+
return `Read ${taskFile} and ${instructionsFile}.
|
|
94
|
+
${visualFeedbackSection}
|
|
95
|
+
${testerFeedbackSection}
|
|
96
|
+
|
|
97
|
+
The tester step found a real problem in the current implementation. Fix only the product behavior related to the current phase and current task.
|
|
98
|
+
|
|
99
|
+
Recent tester findings:
|
|
100
|
+
${recentVerificationOutput}
|
|
101
|
+
|
|
102
|
+
Rules:
|
|
103
|
+
- Start by checking git status so you know which files are already dirty.
|
|
104
|
+
- Do not paper over product bugs by weakening tests.
|
|
105
|
+
- Prefer fixing product code over rewriting tests.
|
|
106
|
+
- Update tests only when the tester exposed a real gap in coverage or testability.
|
|
107
|
+
- Do not create docs, issue templates, or unrelated scaffolding.
|
|
108
|
+
- Do not edit lockfiles or other generated files.
|
|
109
|
+
- If dependencies must change, edit package.json only, then stop.
|
|
110
|
+
- Keep changes minimal and focused on the failing behavior.
|
|
111
|
+
${indentBlock(innerLoopValidationRules(config.testCommand), '\t')}
|
|
112
|
+
- Trust tool results over your own guesses. If a read tool shows file contents, use that exact output instead of arguing with it.
|
|
113
|
+
- Do not repeatedly rewrite the same file because you suspect a formatting issue. Read once, identify the exact mismatch, then make one focused fix.
|
|
114
|
+
${indentBlock(staleEditRecoveryRules(), '\t')}
|
|
115
|
+
- Do not create the final commit during the developer fix pass. Leave the repaired diff for the tester to re-check and commit if it passes.
|
|
116
|
+
|
|
117
|
+
Before stopping:
|
|
118
|
+
- Tick any checkbox in ${taskFile} only if it is now actually complete.
|
|
119
|
+
- Stop after one coherent fix.`
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
export function buildSteeringPrompt(config, reason, options = {}) {
|
|
123
|
+
const taskFile = shortName(config.taskFile)
|
|
124
|
+
const visualFeedbackSection = formatVisualFeedback(options.visualFeedback)
|
|
125
|
+
const testerFeedbackSection = formatTesterFeedback(options.testerFeedback)
|
|
126
|
+
|
|
127
|
+
return `Continue from the current repo state.
|
|
128
|
+
${visualFeedbackSection}
|
|
129
|
+
${testerFeedbackSection}
|
|
130
|
+
|
|
131
|
+
Reason for this follow-up: ${reason}
|
|
132
|
+
|
|
133
|
+
Read ${taskFile}, select the first unchecked actionable checkbox in the current phase, complete one coherent task, tick completed items, run verification, and stop.
|
|
134
|
+
|
|
135
|
+
Additional guardrails:
|
|
136
|
+
- Do not repeat the same tool call over and over.
|
|
137
|
+
- If you already read a file, use that context instead of rereading it unless something changed.
|
|
138
|
+
- If an edit fails once, reread the file before retrying. Do not repeat the same exact edit attempt.
|
|
139
|
+
- Prefer the configured smoke verification path and one narrow targeted check over long full-flow Playwright specs.
|
|
140
|
+
- If you are stuck, make the smallest decisive next action or stop and state the blocker.`
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
export function buildTesterPrompt(config, {
|
|
144
|
+
phase,
|
|
145
|
+
task,
|
|
146
|
+
changedFiles,
|
|
147
|
+
developerNotes,
|
|
148
|
+
reason = 'tester_review',
|
|
149
|
+
visualFeedback = '',
|
|
150
|
+
testerFeedback = '',
|
|
151
|
+
}) {
|
|
152
|
+
const taskFile = shortName(config.taskFile)
|
|
153
|
+
const instructionsFile = shortName(config.testerInstructionsFile)
|
|
154
|
+
const visualFeedbackSection = formatVisualFeedback(visualFeedback)
|
|
155
|
+
const testerFeedbackSection = formatTesterFeedback(testerFeedback)
|
|
156
|
+
const changedFilesSection = changedFiles.length > 0
|
|
157
|
+
? changedFiles.map((file) => `- ${file}`).join('\n')
|
|
158
|
+
: '- No file changes were detected from the developer turn.'
|
|
159
|
+
const verificationCommand = config.testCommand.trim() === '' ? '(not configured)' : config.testCommand
|
|
160
|
+
const visualCaptureNote = config.visualReviewEnabled
|
|
161
|
+
? `\n- Maintain the screenshot capture flow used by the harness (${config.visualCaptureCommand || 'PI_VISUAL_CAPTURE_CMD'}) so current visual artifacts and manifest are produced for visual review.`
|
|
162
|
+
: ''
|
|
163
|
+
|
|
164
|
+
return `Read ${taskFile} and ${instructionsFile}.
|
|
165
|
+
${visualFeedbackSection}
|
|
166
|
+
${testerFeedbackSection}
|
|
167
|
+
|
|
168
|
+
You are the TESTER role. You are reviewing the most recent developer work from an independent quality and functionality perspective.
|
|
169
|
+
|
|
170
|
+
Current phase: ${phase}
|
|
171
|
+
Current task: ${task}
|
|
172
|
+
Reason for this tester pass: ${reason}
|
|
173
|
+
|
|
174
|
+
Developer notes:
|
|
175
|
+
${developerNotes || '(none provided)'}
|
|
176
|
+
|
|
177
|
+
Files changed by the developer:
|
|
178
|
+
${changedFilesSection}
|
|
179
|
+
|
|
180
|
+
Your responsibilities:
|
|
181
|
+
- Inspect the implementation from a skeptical user/tester viewpoint.
|
|
182
|
+
- Add or update verification focused on the changed behavior.
|
|
183
|
+
- Prefer browser-driven checks and targeted tests over broad rewrites.
|
|
184
|
+
- Run the repo verification command yourself: ${verificationCommand}
|
|
185
|
+
${indentBlock(innerLoopValidationRules(verificationCommand), '\t')}
|
|
186
|
+
- Decide whether the feature is actually functionally correct for the intended task, not just whether the code looks plausible.
|
|
187
|
+
- For any user-facing flow, validate the actual playable path in the running app, not just the source code.
|
|
188
|
+
- If the task touches menus, unlocks, progression, classes, routes, shops, onboarding, or gating, verify a fresh-save path so a brand-new player can still start and use the feature.
|
|
189
|
+
${visualCaptureNote}
|
|
190
|
+
|
|
191
|
+
Rules:
|
|
192
|
+
- Start by checking git status so you can separate this task from unrelated dirty files.
|
|
193
|
+
- Prefer editing tests, fixtures, and minimal observability hooks.
|
|
194
|
+
- Avoid editing product code unless a tiny testability hook is essential and does not change user-facing behavior.
|
|
195
|
+
- If you find a real product bug or incomplete functionality, do not hide it with brittle tests.
|
|
196
|
+
- If blocked by tooling or environment, state the blocker clearly.
|
|
197
|
+
- Trust tool results over your own guesses. If a read tool shows file contents, use that exact output instead of arguing with it.
|
|
198
|
+
${indentBlock(staleEditRecoveryRules(), '\t')}
|
|
199
|
+
- Treat "the player cannot start, continue, select, buy, unlock, or exit correctly" as a FAIL even if the code compiles.
|
|
200
|
+
- Before PASS, identify at least one concrete player-visible success path you exercised and one thing you checked for regressions.
|
|
201
|
+
- If your verdict is PASS and the verification command succeeded, do not run git add or git commit yourself. Instead, provide a commit plan for the harness to execute.
|
|
202
|
+
- The commit plan must include only the files related to this task. If the working tree is too messy to isolate safely, use VERDICT: BLOCKED instead of guessing.
|
|
203
|
+
- Use a concise commit message in the format <type>(<scope>): <summary> when possible.
|
|
204
|
+
- Stop after one coherent tester pass.
|
|
205
|
+
|
|
206
|
+
Before the verdict line, include a short section in plain text with:
|
|
207
|
+
- Observed flow:
|
|
208
|
+
- Player-facing result:
|
|
209
|
+
- Regression check:
|
|
210
|
+
|
|
211
|
+
If and only if your verdict is PASS, also include exactly this commit plan block before the verdict line:
|
|
212
|
+
- COMMIT_MESSAGE: <one-line commit message>
|
|
213
|
+
- COMMIT_FILES:
|
|
214
|
+
- path/to/file-one
|
|
215
|
+
- path/to/file-two
|
|
216
|
+
|
|
217
|
+
Before stopping, end your final response with exactly one verdict line:
|
|
218
|
+
- VERDICT: PASS
|
|
219
|
+
- VERDICT: FAIL
|
|
220
|
+
- VERDICT: BLOCKED`
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
export function buildCommitPrompt(config, {
|
|
224
|
+
phase,
|
|
225
|
+
task,
|
|
226
|
+
changedFiles,
|
|
227
|
+
developerNotes,
|
|
228
|
+
reason = 'tester_passed_without_commit',
|
|
229
|
+
visualFeedback = '',
|
|
230
|
+
testerFeedback = '',
|
|
231
|
+
}) {
|
|
232
|
+
const taskFile = shortName(config.taskFile)
|
|
233
|
+
const instructionsFile = shortName(config.testerInstructionsFile)
|
|
234
|
+
const visualFeedbackSection = formatVisualFeedback(visualFeedback)
|
|
235
|
+
const testerFeedbackSection = formatTesterFeedback(testerFeedback)
|
|
236
|
+
const changedFilesSection = changedFiles.length > 0
|
|
237
|
+
? changedFiles.map((file) => `- ${file}`).join('\n')
|
|
238
|
+
: '- No changed files were detected. Inspect git status before deciding whether a commit is possible.'
|
|
239
|
+
|
|
240
|
+
return `Read ${taskFile} and ${instructionsFile}.
|
|
241
|
+
${visualFeedbackSection}
|
|
242
|
+
${testerFeedbackSection}
|
|
243
|
+
|
|
244
|
+
You are the TESTER role. The implementation already passed functional review, but the final commit was not created.
|
|
245
|
+
|
|
246
|
+
Current phase: ${phase}
|
|
247
|
+
Current task: ${task}
|
|
248
|
+
Reason for this follow-up: ${reason}
|
|
249
|
+
|
|
250
|
+
Developer/tester notes:
|
|
251
|
+
${developerNotes || '(none provided)'}
|
|
252
|
+
|
|
253
|
+
Files currently dirty:
|
|
254
|
+
${changedFilesSection}
|
|
255
|
+
|
|
256
|
+
Your job now is commit-plan finalization only. Do not run git commands yourself.
|
|
257
|
+
|
|
258
|
+
Rules:
|
|
259
|
+
- Start by checking git status so you can see exactly which files are dirty.
|
|
260
|
+
- Do not change product code, tests, docs, or TODO items in this pass.
|
|
261
|
+
- Select only the files related to this task.
|
|
262
|
+
- Use a concise commit message in the format <type>(<scope>): <summary> when possible.
|
|
263
|
+
- If the working tree is too messy to isolate safely, do not guess. End with VERDICT: BLOCKED.
|
|
264
|
+
|
|
265
|
+
If you can isolate the correct commit, include exactly this block before the verdict line:
|
|
266
|
+
- COMMIT_MESSAGE: <one-line commit message>
|
|
267
|
+
- COMMIT_FILES:
|
|
268
|
+
- path/to/file-one
|
|
269
|
+
- path/to/file-two
|
|
270
|
+
|
|
271
|
+
Before stopping, end your final response with exactly one verdict line:
|
|
272
|
+
- VERDICT: PASS
|
|
273
|
+
- VERDICT: BLOCKED`
|
|
274
|
+
}
|