@virtengine/openfleet 0.25.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/.env.example +914 -0
- package/LICENSE +190 -0
- package/README.md +500 -0
- package/agent-endpoint.mjs +918 -0
- package/agent-hook-bridge.mjs +230 -0
- package/agent-hooks.mjs +1188 -0
- package/agent-pool.mjs +2403 -0
- package/agent-prompts.mjs +689 -0
- package/agent-sdk.mjs +141 -0
- package/anomaly-detector.mjs +1195 -0
- package/autofix.mjs +1294 -0
- package/claude-shell.mjs +708 -0
- package/cli.mjs +906 -0
- package/codex-config.mjs +1274 -0
- package/codex-model-profiles.mjs +135 -0
- package/codex-shell.mjs +762 -0
- package/config-doctor.mjs +613 -0
- package/config.mjs +1720 -0
- package/conflict-resolver.mjs +248 -0
- package/container-runner.mjs +450 -0
- package/copilot-shell.mjs +827 -0
- package/daemon-restart-policy.mjs +56 -0
- package/diff-stats.mjs +282 -0
- package/error-detector.mjs +829 -0
- package/fetch-runtime.mjs +34 -0
- package/fleet-coordinator.mjs +838 -0
- package/get-telegram-chat-id.mjs +71 -0
- package/git-safety.mjs +170 -0
- package/github-reconciler.mjs +403 -0
- package/hook-profiles.mjs +651 -0
- package/kanban-adapter.mjs +4491 -0
- package/lib/logger.mjs +645 -0
- package/maintenance.mjs +828 -0
- package/merge-strategy.mjs +1171 -0
- package/monitor.mjs +12207 -0
- package/openfleet.config.example.json +115 -0
- package/openfleet.schema.json +465 -0
- package/package.json +203 -0
- package/postinstall.mjs +187 -0
- package/pr-cleanup-daemon.mjs +978 -0
- package/preflight.mjs +408 -0
- package/prepublish-check.mjs +90 -0
- package/presence.mjs +328 -0
- package/primary-agent.mjs +282 -0
- package/publish.mjs +151 -0
- package/repo-root.mjs +29 -0
- package/restart-controller.mjs +100 -0
- package/review-agent.mjs +557 -0
- package/rotate-agent-logs.sh +133 -0
- package/sdk-conflict-resolver.mjs +973 -0
- package/session-tracker.mjs +880 -0
- package/setup.mjs +3937 -0
- package/shared-knowledge.mjs +410 -0
- package/shared-state-manager.mjs +841 -0
- package/shared-workspace-cli.mjs +199 -0
- package/shared-workspace-registry.mjs +537 -0
- package/shared-workspaces.json +18 -0
- package/startup-service.mjs +1070 -0
- package/sync-engine.mjs +1063 -0
- package/task-archiver.mjs +801 -0
- package/task-assessment.mjs +550 -0
- package/task-claims.mjs +924 -0
- package/task-complexity.mjs +581 -0
- package/task-executor.mjs +5111 -0
- package/task-store.mjs +753 -0
- package/telegram-bot.mjs +9281 -0
- package/telegram-sentinel.mjs +2010 -0
- package/ui/app.js +867 -0
- package/ui/app.legacy.js +1464 -0
- package/ui/app.monolith.js +2488 -0
- package/ui/components/charts.js +226 -0
- package/ui/components/chat-view.js +567 -0
- package/ui/components/command-palette.js +587 -0
- package/ui/components/diff-viewer.js +190 -0
- package/ui/components/forms.js +327 -0
- package/ui/components/kanban-board.js +451 -0
- package/ui/components/session-list.js +305 -0
- package/ui/components/shared.js +473 -0
- package/ui/index.html +70 -0
- package/ui/modules/api.js +297 -0
- package/ui/modules/icons.js +461 -0
- package/ui/modules/router.js +81 -0
- package/ui/modules/settings-schema.js +261 -0
- package/ui/modules/state.js +679 -0
- package/ui/modules/telegram.js +331 -0
- package/ui/modules/utils.js +270 -0
- package/ui/styles/animations.css +140 -0
- package/ui/styles/base.css +98 -0
- package/ui/styles/components.css +1915 -0
- package/ui/styles/kanban.css +286 -0
- package/ui/styles/layout.css +809 -0
- package/ui/styles/sessions.css +827 -0
- package/ui/styles/variables.css +188 -0
- package/ui/styles.css +141 -0
- package/ui/styles.monolith.css +1046 -0
- package/ui/tabs/agents.js +1417 -0
- package/ui/tabs/chat.js +74 -0
- package/ui/tabs/control.js +887 -0
- package/ui/tabs/dashboard.js +515 -0
- package/ui/tabs/infra.js +537 -0
- package/ui/tabs/logs.js +783 -0
- package/ui/tabs/settings.js +1487 -0
- package/ui/tabs/tasks.js +1385 -0
- package/ui-server.mjs +4073 -0
- package/update-check.mjs +465 -0
- package/utils.mjs +172 -0
- package/ve-kanban.mjs +654 -0
- package/ve-kanban.ps1 +1365 -0
- package/ve-kanban.sh +18 -0
- package/ve-orchestrator.mjs +340 -0
- package/ve-orchestrator.ps1 +6546 -0
- package/ve-orchestrator.sh +18 -0
- package/vibe-kanban-wrapper.mjs +41 -0
- package/vk-error-resolver.mjs +470 -0
- package/vk-log-stream.mjs +914 -0
- package/whatsapp-channel.mjs +520 -0
- package/workspace-monitor.mjs +581 -0
- package/workspace-reaper.mjs +405 -0
- package/workspace-registry.mjs +238 -0
- package/worktree-manager.mjs +1266 -0
|
@@ -0,0 +1,689 @@
|
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { resolve, isAbsolute } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
|
|
5
|
+
function toEnvSuffix(key) {
|
|
6
|
+
return String(key)
|
|
7
|
+
.replace(/([a-z0-9])([A-Z])/g, "$1_$2")
|
|
8
|
+
.replace(/[^A-Za-z0-9]+/g, "_")
|
|
9
|
+
.toUpperCase();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const PROMPT_WORKSPACE_DIR = ".openfleet/agents";
|
|
13
|
+
|
|
14
|
+
const PROMPT_DEFS = [
|
|
15
|
+
{
|
|
16
|
+
key: "orchestrator",
|
|
17
|
+
filename: "orchestrator.md",
|
|
18
|
+
description: "Primary task execution prompt for autonomous task agents.",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
key: "planner",
|
|
22
|
+
filename: "task-planner.md",
|
|
23
|
+
description: "Backlog planning prompt used by task planner runs.",
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
key: "monitorMonitor",
|
|
27
|
+
filename: "monitor-monitor.md",
|
|
28
|
+
description: "Long-running reliability monitor prompt used in devmode.",
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
key: "taskExecutor",
|
|
32
|
+
filename: "task-executor.md",
|
|
33
|
+
description: "Task execution prompt used for actual implementation runs.",
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
key: "taskExecutorRetry",
|
|
37
|
+
filename: "task-executor-retry.md",
|
|
38
|
+
description: "Recovery prompt after a failed task execution attempt.",
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
key: "taskExecutorContinueHasCommits",
|
|
42
|
+
filename: "task-executor-continue-has-commits.md",
|
|
43
|
+
description:
|
|
44
|
+
"Continue prompt when edits were committed but not fully finalized.",
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
key: "taskExecutorContinueHasEdits",
|
|
48
|
+
filename: "task-executor-continue-has-edits.md",
|
|
49
|
+
description: "Continue prompt when uncommitted edits exist.",
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
key: "taskExecutorContinueNoProgress",
|
|
53
|
+
filename: "task-executor-continue-no-progress.md",
|
|
54
|
+
description:
|
|
55
|
+
"Continue prompt when the task stalled without meaningful progress.",
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
key: "reviewer",
|
|
59
|
+
filename: "reviewer.md",
|
|
60
|
+
description: "Prompt used by automated review agent.",
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
key: "conflictResolver",
|
|
64
|
+
filename: "conflict-resolver.md",
|
|
65
|
+
description: "Prompt used for rebase conflict follow-up guidance.",
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
key: "sdkConflictResolver",
|
|
69
|
+
filename: "sdk-conflict-resolver.md",
|
|
70
|
+
description: "Prompt for SDK-driven merge conflict resolution sessions.",
|
|
71
|
+
},
|
|
72
|
+
{
|
|
73
|
+
key: "mergeStrategy",
|
|
74
|
+
filename: "merge-strategy.md",
|
|
75
|
+
description: "Prompt for merge strategy analysis and decisioning.",
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
key: "mergeStrategyFix",
|
|
79
|
+
filename: "merge-strategy-fix.md",
|
|
80
|
+
description:
|
|
81
|
+
"Prompt used when merge strategy decides to send a fix message.",
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
key: "mergeStrategyReAttempt",
|
|
85
|
+
filename: "merge-strategy-reattempt.md",
|
|
86
|
+
description:
|
|
87
|
+
"Prompt used when merge strategy decides to re-attempt the task.",
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
key: "autofixFix",
|
|
91
|
+
filename: "autofix-fix.md",
|
|
92
|
+
description:
|
|
93
|
+
"Prompt used by crash autofix when structured error data is available.",
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
key: "autofixFallback",
|
|
97
|
+
filename: "autofix-fallback.md",
|
|
98
|
+
description:
|
|
99
|
+
"Prompt used by crash autofix when only log-tail context is available.",
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
key: "autofixLoop",
|
|
103
|
+
filename: "autofix-loop.md",
|
|
104
|
+
description: "Prompt used by repeating-error loop fixer.",
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
key: "monitorCrashFix",
|
|
108
|
+
filename: "monitor-crash-fix.md",
|
|
109
|
+
description: "Prompt used when monitor process crashes unexpectedly.",
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
key: "monitorRestartLoopFix",
|
|
113
|
+
filename: "monitor-restart-loop-fix.md",
|
|
114
|
+
description: "Prompt used when monitor/orchestrator enters restart loops.",
|
|
115
|
+
},
|
|
116
|
+
];
|
|
117
|
+
|
|
118
|
+
export const AGENT_PROMPT_DEFINITIONS = Object.freeze(
|
|
119
|
+
PROMPT_DEFS.map((item) =>
|
|
120
|
+
Object.freeze({
|
|
121
|
+
...item,
|
|
122
|
+
envVar: `CODEX_MONITOR_PROMPT_${toEnvSuffix(item.key)}`,
|
|
123
|
+
defaultRelativePath: `${PROMPT_WORKSPACE_DIR}/${item.filename}`,
|
|
124
|
+
}),
|
|
125
|
+
),
|
|
126
|
+
);
|
|
127
|
+
|
|
128
|
+
const DEFAULT_PROMPTS = {
|
|
129
|
+
orchestrator: `# Task Orchestrator Agent
|
|
130
|
+
|
|
131
|
+
You are an autonomous task orchestrator agent. You receive implementation tasks and execute them end-to-end.
|
|
132
|
+
|
|
133
|
+
## Prime Directives
|
|
134
|
+
|
|
135
|
+
1. Never ask for human input for normal engineering decisions.
|
|
136
|
+
2. Complete the assigned scope fully before stopping.
|
|
137
|
+
3. Keep changes minimal, correct, and production-safe.
|
|
138
|
+
4. Run relevant verification (tests/lint/build) before finalizing.
|
|
139
|
+
5. Use conventional commit messages.
|
|
140
|
+
|
|
141
|
+
## Completion Criteria
|
|
142
|
+
|
|
143
|
+
- Implementation matches requested behavior.
|
|
144
|
+
- Existing functionality is preserved.
|
|
145
|
+
- Relevant checks pass.
|
|
146
|
+
- Branch is pushed and ready for PR/review flow.
|
|
147
|
+
`,
|
|
148
|
+
planner: `# Codex-Task-Planner Agent
|
|
149
|
+
|
|
150
|
+
You generate production-grade backlog tasks for autonomous executors.
|
|
151
|
+
|
|
152
|
+
## Mission
|
|
153
|
+
|
|
154
|
+
1. Analyze current repo and delivery state.
|
|
155
|
+
2. Identify highest-value next work.
|
|
156
|
+
3. Create concrete, execution-ready tasks.
|
|
157
|
+
|
|
158
|
+
## Requirements
|
|
159
|
+
|
|
160
|
+
- Avoid vague tasks and duplicate work.
|
|
161
|
+
- Balance reliability fixes, feature delivery, and debt reduction.
|
|
162
|
+
- Every task includes implementation steps, acceptance criteria, and verification plan.
|
|
163
|
+
- Every task title starts with one size label: [xs], [s], [m], [l], [xl], [xxl].
|
|
164
|
+
- Prefer task sets that can run in parallel with low file overlap.
|
|
165
|
+
- Do not call any kanban API, CLI, or external service to create tasks.
|
|
166
|
+
- Output must be machine-parseable JSON in a fenced json block.
|
|
167
|
+
|
|
168
|
+
## Output Contract (Mandatory)
|
|
169
|
+
|
|
170
|
+
Return exactly one fenced json block with this shape:
|
|
171
|
+
|
|
172
|
+
\`\`\`json
|
|
173
|
+
{
|
|
174
|
+
"tasks": [
|
|
175
|
+
{
|
|
176
|
+
"title": "[m] Example task title",
|
|
177
|
+
"description": "Problem statement and scope",
|
|
178
|
+
"implementation_steps": ["step 1", "step 2"],
|
|
179
|
+
"acceptance_criteria": ["criterion 1", "criterion 2"],
|
|
180
|
+
"verification": ["test/check 1", "test/check 2"]
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
\`\`\`
|
|
185
|
+
|
|
186
|
+
Rules:
|
|
187
|
+
- Provide at least the requested task count unless blocked by duplicate safeguards.
|
|
188
|
+
- Keep titles unique and specific.
|
|
189
|
+
- Keep file overlap low across tasks to maximize parallel execution.
|
|
190
|
+
`,
|
|
191
|
+
monitorMonitor: `# OpenFleet-Monitor Agent
|
|
192
|
+
|
|
193
|
+
You are the always-on reliability guardian for openfleet in devmode.
|
|
194
|
+
|
|
195
|
+
## Core Role
|
|
196
|
+
|
|
197
|
+
- Monitor logs, failures, and agent/orchestrator behavior continuously.
|
|
198
|
+
- Immediately fix reliability regressions and execution blockers.
|
|
199
|
+
- Improve prompt/tool/executor reliability to reduce failure loops.
|
|
200
|
+
- Only when runtime is healthy, perform code-analysis improvements.
|
|
201
|
+
|
|
202
|
+
## Constraints
|
|
203
|
+
|
|
204
|
+
- Operate only in devmode.
|
|
205
|
+
- Do not commit/push/open PRs in this context.
|
|
206
|
+
- Apply focused fixes, run focused validation, and keep monitoring.
|
|
207
|
+
`,
|
|
208
|
+
taskExecutor: `# {{TASK_ID}} — {{TASK_TITLE}}
|
|
209
|
+
|
|
210
|
+
## Description
|
|
211
|
+
{{TASK_DESCRIPTION}}
|
|
212
|
+
|
|
213
|
+
## Environment
|
|
214
|
+
- Working Directory: {{WORKTREE_PATH}}
|
|
215
|
+
- Branch: {{BRANCH}}
|
|
216
|
+
- Repository: {{REPO_SLUG}}
|
|
217
|
+
|
|
218
|
+
## Instructions
|
|
219
|
+
1. Read task requirements carefully.
|
|
220
|
+
2. Implement required code changes.
|
|
221
|
+
3. Run relevant tests/lint/build checks.
|
|
222
|
+
4. Commit with conventional commit format.
|
|
223
|
+
5. Push branch updates.
|
|
224
|
+
|
|
225
|
+
## Critical Rules
|
|
226
|
+
- Do not ask for manual confirmation.
|
|
227
|
+
- No placeholders/stubs/TODO-only output.
|
|
228
|
+
- Keep behavior stable and production-safe.
|
|
229
|
+
|
|
230
|
+
## Agent Status Endpoint
|
|
231
|
+
- URL: http://127.0.0.1:{{ENDPOINT_PORT}}/api/tasks/{{TASK_ID}}
|
|
232
|
+
- POST /status {"status":"inreview"} after PR-ready push
|
|
233
|
+
- POST /heartbeat {} while running
|
|
234
|
+
- POST /error {"error":"..."} on fatal failure
|
|
235
|
+
- POST /complete {"hasCommits":true} when done
|
|
236
|
+
|
|
237
|
+
## Task Reference
|
|
238
|
+
{{TASK_URL_LINE}}
|
|
239
|
+
|
|
240
|
+
## Repository Context
|
|
241
|
+
{{REPO_CONTEXT}}
|
|
242
|
+
`,
|
|
243
|
+
taskExecutorRetry: `# {{TASK_ID}} — ERROR RECOVERY (Attempt {{ATTEMPT_NUMBER}})
|
|
244
|
+
|
|
245
|
+
Your previous attempt on task "{{TASK_TITLE}}" encountered an issue:
|
|
246
|
+
|
|
247
|
+
\`\`\`
|
|
248
|
+
{{LAST_ERROR}}
|
|
249
|
+
\`\`\`
|
|
250
|
+
|
|
251
|
+
Error classification: {{CLASSIFICATION_PATTERN}} (confidence: {{CLASSIFICATION_CONFIDENCE}})
|
|
252
|
+
|
|
253
|
+
Please:
|
|
254
|
+
1. Diagnose the failure root cause.
|
|
255
|
+
2. Fix the issue with minimal safe changes.
|
|
256
|
+
3. Re-run verification checks.
|
|
257
|
+
4. Commit and push the fix.
|
|
258
|
+
|
|
259
|
+
Original task description:
|
|
260
|
+
{{TASK_DESCRIPTION}}
|
|
261
|
+
`,
|
|
262
|
+
taskExecutorContinueHasCommits: `# {{TASK_ID}} — CONTINUE (Verify and Push)
|
|
263
|
+
|
|
264
|
+
You were working on "{{TASK_TITLE}}" and appear to have stopped.
|
|
265
|
+
You already made commits.
|
|
266
|
+
|
|
267
|
+
1. Run tests to verify changes.
|
|
268
|
+
2. If passing, push: git push origin HEAD
|
|
269
|
+
3. If failing, fix issues, commit, and push.
|
|
270
|
+
4. Task is not complete until push succeeds.
|
|
271
|
+
`,
|
|
272
|
+
taskExecutorContinueHasEdits: `# {{TASK_ID}} — CONTINUE (Commit and Push)
|
|
273
|
+
|
|
274
|
+
You were working on "{{TASK_TITLE}}" and appear to have stopped.
|
|
275
|
+
You made file edits but no commit yet.
|
|
276
|
+
|
|
277
|
+
1. Review edits for correctness.
|
|
278
|
+
2. Run relevant tests.
|
|
279
|
+
3. Commit with conventional format.
|
|
280
|
+
4. Push: git push origin HEAD
|
|
281
|
+
`,
|
|
282
|
+
taskExecutorContinueNoProgress: `# CONTINUE - Resume Implementation
|
|
283
|
+
|
|
284
|
+
You were working on "{{TASK_TITLE}}" but stopped without meaningful progress.
|
|
285
|
+
|
|
286
|
+
Execute now:
|
|
287
|
+
1. Read relevant source files.
|
|
288
|
+
2. Implement required changes.
|
|
289
|
+
3. Run verification checks.
|
|
290
|
+
4. Commit with conventional format.
|
|
291
|
+
5. Push to current branch.
|
|
292
|
+
|
|
293
|
+
Task: {{TASK_TITLE}}
|
|
294
|
+
Description: {{TASK_DESCRIPTION}}
|
|
295
|
+
`,
|
|
296
|
+
reviewer: `You are a senior code reviewer for a production software project.
|
|
297
|
+
|
|
298
|
+
Review the following PR diff for CRITICAL issues ONLY.
|
|
299
|
+
|
|
300
|
+
## What to flag
|
|
301
|
+
1. Security vulnerabilities
|
|
302
|
+
2. Bugs / correctness regressions
|
|
303
|
+
3. Missing implementations
|
|
304
|
+
4. Broken functionality
|
|
305
|
+
|
|
306
|
+
## What to ignore
|
|
307
|
+
- Style-only concerns
|
|
308
|
+
- Naming-only concerns
|
|
309
|
+
- Minor refactor ideas
|
|
310
|
+
- Non-critical perf suggestions
|
|
311
|
+
- Documentation-only gaps
|
|
312
|
+
|
|
313
|
+
## PR Diff
|
|
314
|
+
\`\`\`diff
|
|
315
|
+
{{DIFF}}
|
|
316
|
+
\`\`\`
|
|
317
|
+
|
|
318
|
+
## Task Description
|
|
319
|
+
{{TASK_DESCRIPTION}}
|
|
320
|
+
|
|
321
|
+
## Response Format
|
|
322
|
+
Respond with JSON only:
|
|
323
|
+
{
|
|
324
|
+
"verdict": "approved" | "changes_requested",
|
|
325
|
+
"issues": [
|
|
326
|
+
{
|
|
327
|
+
"severity": "critical" | "major",
|
|
328
|
+
"category": "security" | "bug" | "missing_impl" | "broken",
|
|
329
|
+
"file": "path/to/file",
|
|
330
|
+
"line": 123,
|
|
331
|
+
"description": "..."
|
|
332
|
+
}
|
|
333
|
+
],
|
|
334
|
+
"summary": "One sentence overall assessment"
|
|
335
|
+
}
|
|
336
|
+
`,
|
|
337
|
+
conflictResolver: `Conflicts detected while rebasing onto {{UPSTREAM_BRANCH}}.
|
|
338
|
+
Auto-resolve summary: {{AUTO_RESOLVE_SUMMARY}}.
|
|
339
|
+
|
|
340
|
+
{{MANUAL_CONFLICTS_SECTION}}
|
|
341
|
+
|
|
342
|
+
Use 'git checkout --theirs <file>' for lockfiles and 'git checkout --ours <file>' for CHANGELOG.md/coverage.txt/results.txt.
|
|
343
|
+
`,
|
|
344
|
+
sdkConflictResolver: `# Merge Conflict Resolution
|
|
345
|
+
|
|
346
|
+
You are resolving merge conflicts in a git worktree.
|
|
347
|
+
|
|
348
|
+
## Context
|
|
349
|
+
- Working directory: {{WORKTREE_PATH}}
|
|
350
|
+
- PR branch (HEAD): {{BRANCH}}
|
|
351
|
+
- Base branch (incoming): origin/{{BASE_BRANCH}}
|
|
352
|
+
{{PR_LINE}}
|
|
353
|
+
{{TASK_TITLE_LINE}}
|
|
354
|
+
{{TASK_DESCRIPTION_LINE}}
|
|
355
|
+
|
|
356
|
+
## Merge State
|
|
357
|
+
A merge is already in progress. Do not start a new merge or rebase.
|
|
358
|
+
|
|
359
|
+
{{AUTO_FILES_SECTION}}
|
|
360
|
+
|
|
361
|
+
{{MANUAL_FILES_SECTION}}
|
|
362
|
+
|
|
363
|
+
## After Resolving All Files
|
|
364
|
+
1. Ensure no conflict markers remain.
|
|
365
|
+
2. Commit merge result.
|
|
366
|
+
3. Push: git push origin HEAD:{{BRANCH}}
|
|
367
|
+
|
|
368
|
+
## Critical Rules
|
|
369
|
+
- Do not abort merge.
|
|
370
|
+
- Do not run merge again.
|
|
371
|
+
- Do not use rebase for this recovery.
|
|
372
|
+
- Preserve behavior from both sides where possible.
|
|
373
|
+
`,
|
|
374
|
+
mergeStrategy: `# Merge Strategy Decision
|
|
375
|
+
|
|
376
|
+
You are a senior engineering reviewer. An AI agent has completed (or attempted) a task.
|
|
377
|
+
Review the context and decide the next action.
|
|
378
|
+
|
|
379
|
+
{{TASK_CONTEXT_BLOCK}}
|
|
380
|
+
{{AGENT_LAST_MESSAGE_BLOCK}}
|
|
381
|
+
{{PULL_REQUEST_BLOCK}}
|
|
382
|
+
{{CHANGES_BLOCK}}
|
|
383
|
+
{{CHANGED_FILES_BLOCK}}
|
|
384
|
+
{{DIFF_STATS_BLOCK}}
|
|
385
|
+
{{WORKTREE_BLOCK}}
|
|
386
|
+
|
|
387
|
+
## Decision Rules
|
|
388
|
+
Return exactly one action:
|
|
389
|
+
- merge_after_ci_pass
|
|
390
|
+
- prompt
|
|
391
|
+
- close_pr
|
|
392
|
+
- re_attempt
|
|
393
|
+
- manual_review
|
|
394
|
+
- wait
|
|
395
|
+
- noop
|
|
396
|
+
|
|
397
|
+
Respond with JSON only.
|
|
398
|
+
`,
|
|
399
|
+
mergeStrategyFix: `# Fix Required
|
|
400
|
+
|
|
401
|
+
{{TASK_CONTEXT_BLOCK}}
|
|
402
|
+
|
|
403
|
+
## Fix Instruction
|
|
404
|
+
{{FIX_MESSAGE}}
|
|
405
|
+
|
|
406
|
+
{{CI_STATUS_LINE}}
|
|
407
|
+
|
|
408
|
+
After fixing:
|
|
409
|
+
1. Run relevant checks.
|
|
410
|
+
2. Commit with clear message.
|
|
411
|
+
3. Push updates.
|
|
412
|
+
`,
|
|
413
|
+
mergeStrategyReAttempt: `# Task Re-Attempt
|
|
414
|
+
|
|
415
|
+
A previous attempt failed.
|
|
416
|
+
|
|
417
|
+
{{TASK_CONTEXT_BLOCK}}
|
|
418
|
+
|
|
419
|
+
Failure reason: {{FAILURE_REASON}}
|
|
420
|
+
|
|
421
|
+
Start fresh, complete task, verify, commit, and push.
|
|
422
|
+
`,
|
|
423
|
+
autofixFix: `You are a PowerShell expert fixing a crash in a running orchestrator script.
|
|
424
|
+
|
|
425
|
+
## Error
|
|
426
|
+
Type: {{ERROR_TYPE}}
|
|
427
|
+
File: {{ERROR_FILE}}
|
|
428
|
+
Line: {{ERROR_LINE}}
|
|
429
|
+
{{ERROR_COLUMN_LINE}}
|
|
430
|
+
Message: {{ERROR_MESSAGE}}
|
|
431
|
+
{{ERROR_CODE_LINE}}
|
|
432
|
+
Crash reason: {{CRASH_REASON}}
|
|
433
|
+
|
|
434
|
+
## Source context around line {{ERROR_LINE}}
|
|
435
|
+
\`\`\`powershell
|
|
436
|
+
{{SOURCE_CONTEXT}}
|
|
437
|
+
\`\`\`
|
|
438
|
+
{{RECENT_MESSAGES_CONTEXT}}
|
|
439
|
+
## Instructions
|
|
440
|
+
1. Read file {{ERROR_FILE}}.
|
|
441
|
+
2. Identify root cause.
|
|
442
|
+
3. Apply minimal safe fix only.
|
|
443
|
+
4. Preserve existing behavior.
|
|
444
|
+
5. Write fix directly in file.
|
|
445
|
+
`,
|
|
446
|
+
autofixFallback: `You are a PowerShell expert analyzing an orchestrator crash.
|
|
447
|
+
No structured error was extracted. Termination reason: {{FALLBACK_REASON}}
|
|
448
|
+
|
|
449
|
+
## Error indicators from log tail
|
|
450
|
+
{{FALLBACK_ERROR_LINES}}
|
|
451
|
+
|
|
452
|
+
## Last {{FALLBACK_LINE_COUNT}} lines of crash log
|
|
453
|
+
\`\`\`
|
|
454
|
+
{{FALLBACK_TAIL}}
|
|
455
|
+
\`\`\`
|
|
456
|
+
{{RECENT_MESSAGES_CONTEXT}}
|
|
457
|
+
## Instructions
|
|
458
|
+
1. Analyze likely root cause.
|
|
459
|
+
2. Main script: scripts/openfleet/ve-orchestrator.ps1
|
|
460
|
+
3. If fixable bug exists, apply minimal safe fix.
|
|
461
|
+
4. If crash is external only (OOM/SIGKILL), do not modify code.
|
|
462
|
+
`,
|
|
463
|
+
autofixLoop: `You are a PowerShell expert fixing a loop bug in a running orchestrator script.
|
|
464
|
+
|
|
465
|
+
## Problem
|
|
466
|
+
This error repeats {{REPEAT_COUNT}} times:
|
|
467
|
+
"{{ERROR_LINE}}"
|
|
468
|
+
|
|
469
|
+
{{RECENT_MESSAGES_CONTEXT}}
|
|
470
|
+
|
|
471
|
+
## Instructions
|
|
472
|
+
1. Main script: scripts/openfleet/ve-orchestrator.ps1
|
|
473
|
+
2. Find where this error is emitted.
|
|
474
|
+
3. Fix loop root cause (missing state change, missing stop condition, etc).
|
|
475
|
+
4. Apply minimal safe fix only.
|
|
476
|
+
5. Write fix directly in file.
|
|
477
|
+
`,
|
|
478
|
+
monitorCrashFix: `You are debugging {{PROJECT_NAME}} openfleet.
|
|
479
|
+
|
|
480
|
+
The monitor process hit an unexpected exception and needs a fix.
|
|
481
|
+
Inspect and fix code in openfleet modules.
|
|
482
|
+
|
|
483
|
+
Crash info:
|
|
484
|
+
{{CRASH_INFO}}
|
|
485
|
+
|
|
486
|
+
Recent log context:
|
|
487
|
+
{{LOG_TAIL}}
|
|
488
|
+
|
|
489
|
+
Instructions:
|
|
490
|
+
1. Identify root cause.
|
|
491
|
+
2. Apply minimal production-safe fix.
|
|
492
|
+
3. Do not refactor unrelated code.
|
|
493
|
+
`,
|
|
494
|
+
monitorRestartLoopFix: `You are a reliability engineer debugging a crash loop in {{PROJECT_NAME}} automation.
|
|
495
|
+
|
|
496
|
+
The orchestrator is restarting repeatedly within minutes.
|
|
497
|
+
Diagnose likely root cause and apply a minimal fix.
|
|
498
|
+
|
|
499
|
+
Targets (edit only if needed):
|
|
500
|
+
- {{SCRIPT_PATH}}
|
|
501
|
+
- openfleet/monitor.mjs
|
|
502
|
+
- openfleet/autofix.mjs
|
|
503
|
+
- openfleet/maintenance.mjs
|
|
504
|
+
|
|
505
|
+
Recent log excerpt:
|
|
506
|
+
{{LOG_TAIL}}
|
|
507
|
+
|
|
508
|
+
Constraints:
|
|
509
|
+
1. Prevent rapid restart loops.
|
|
510
|
+
2. Keep behavior stable and production-safe.
|
|
511
|
+
3. Avoid unrelated refactors.
|
|
512
|
+
4. Prefer small guardrails.
|
|
513
|
+
`,
|
|
514
|
+
};
|
|
515
|
+
|
|
516
|
+
function normalizeTemplateValue(value) {
|
|
517
|
+
if (value == null) return "";
|
|
518
|
+
if (typeof value === "string") return value;
|
|
519
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
520
|
+
return String(value);
|
|
521
|
+
}
|
|
522
|
+
try {
|
|
523
|
+
return JSON.stringify(value, null, 2);
|
|
524
|
+
} catch {
|
|
525
|
+
return String(value);
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
function asPathCandidates(pathValue, configDir, repoRoot) {
|
|
530
|
+
if (!pathValue || typeof pathValue !== "string") return [];
|
|
531
|
+
const raw = pathValue.trim();
|
|
532
|
+
if (!raw) return [];
|
|
533
|
+
if (raw.startsWith("~")) {
|
|
534
|
+
const home = process.env.HOME || process.env.USERPROFILE || "";
|
|
535
|
+
return [resolve(home, raw.slice(1))];
|
|
536
|
+
}
|
|
537
|
+
if (isAbsolute(raw)) return [resolve(raw)];
|
|
538
|
+
|
|
539
|
+
const candidates = [];
|
|
540
|
+
if (repoRoot) candidates.push(resolve(repoRoot, raw));
|
|
541
|
+
if (configDir) candidates.push(resolve(configDir, raw));
|
|
542
|
+
candidates.push(resolve(process.cwd(), raw));
|
|
543
|
+
|
|
544
|
+
return candidates.filter((p, idx, arr) => p && arr.indexOf(p) === idx);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
function readTemplateFile(candidates) {
|
|
548
|
+
for (const filePath of candidates) {
|
|
549
|
+
if (!existsSync(filePath)) continue;
|
|
550
|
+
try {
|
|
551
|
+
return { content: readFileSync(filePath, "utf8"), path: filePath };
|
|
552
|
+
} catch {
|
|
553
|
+
// Continue to next candidate.
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
return null;
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
export function getAgentPromptDefinitions() {
|
|
560
|
+
return AGENT_PROMPT_DEFINITIONS;
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
export function getDefaultPromptWorkspace(repoRoot) {
|
|
564
|
+
const override = String(
|
|
565
|
+
process.env.CODEX_MONITOR_PROMPT_WORKSPACE || "",
|
|
566
|
+
).trim();
|
|
567
|
+
if (override) {
|
|
568
|
+
return isAbsolute(override)
|
|
569
|
+
? override
|
|
570
|
+
: resolve(repoRoot || process.cwd(), override);
|
|
571
|
+
}
|
|
572
|
+
return resolve(repoRoot || process.cwd(), PROMPT_WORKSPACE_DIR);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
export function getDefaultPromptTemplate(key) {
|
|
576
|
+
return DEFAULT_PROMPTS[key] || "";
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
export function renderPromptTemplate(template, values = {}) {
|
|
580
|
+
if (typeof template !== "string") return "";
|
|
581
|
+
const normalized = {};
|
|
582
|
+
for (const [k, v] of Object.entries(values || {})) {
|
|
583
|
+
normalized[String(k).trim().toUpperCase()] = normalizeTemplateValue(v);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
return template.replace(/\{\{\s*([A-Za-z0-9_]+)\s*\}\}/g, (full, key) => {
|
|
587
|
+
const hit = normalized[String(key).toUpperCase()];
|
|
588
|
+
return hit == null ? "" : hit;
|
|
589
|
+
});
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
export function resolvePromptTemplate(template, values, fallback) {
|
|
593
|
+
const base = typeof fallback === "string" ? fallback : "";
|
|
594
|
+
if (typeof template !== "string" || !template.trim()) return base;
|
|
595
|
+
const rendered = renderPromptTemplate(template, {
|
|
596
|
+
...(values || {}),
|
|
597
|
+
DEFAULT_PROMPT: base,
|
|
598
|
+
});
|
|
599
|
+
return rendered && rendered.trim() ? rendered : base;
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
export function ensureAgentPromptWorkspace(repoRoot) {
|
|
603
|
+
const root = resolve(repoRoot || process.cwd());
|
|
604
|
+
let workspaceDir = getDefaultPromptWorkspace(root);
|
|
605
|
+
|
|
606
|
+
try {
|
|
607
|
+
mkdirSync(workspaceDir, { recursive: true });
|
|
608
|
+
} catch (err) {
|
|
609
|
+
const fallbackRoot = resolve(
|
|
610
|
+
process.env.CODEX_MONITOR_HOME ||
|
|
611
|
+
process.env.HOME ||
|
|
612
|
+
process.env.USERPROFILE ||
|
|
613
|
+
homedir(),
|
|
614
|
+
);
|
|
615
|
+
const fallbackDir = resolve(fallbackRoot, PROMPT_WORKSPACE_DIR);
|
|
616
|
+
process.env.CODEX_MONITOR_PROMPT_WORKSPACE = fallbackDir;
|
|
617
|
+
workspaceDir = fallbackDir;
|
|
618
|
+
mkdirSync(workspaceDir, { recursive: true });
|
|
619
|
+
console.warn(
|
|
620
|
+
`[agent-prompts] prompt workspace fallback enabled: ${workspaceDir} (primary path failed: ${err?.code || err?.message || err})`,
|
|
621
|
+
);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
const written = [];
|
|
625
|
+
for (const def of AGENT_PROMPT_DEFINITIONS) {
|
|
626
|
+
const filePath = resolve(workspaceDir, def.filename);
|
|
627
|
+
if (existsSync(filePath)) continue;
|
|
628
|
+
|
|
629
|
+
const body = [
|
|
630
|
+
`<!-- openfleet prompt: ${def.key} -->`,
|
|
631
|
+
`<!-- ${def.description} -->`,
|
|
632
|
+
"",
|
|
633
|
+
DEFAULT_PROMPTS[def.key] || "",
|
|
634
|
+
"",
|
|
635
|
+
].join("\n");
|
|
636
|
+
|
|
637
|
+
writeFileSync(filePath, body, "utf8");
|
|
638
|
+
written.push(filePath);
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
return {
|
|
642
|
+
workspaceDir,
|
|
643
|
+
written,
|
|
644
|
+
};
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
export function resolveAgentPrompts(configDir, repoRoot, configData = {}) {
|
|
648
|
+
const workspaceDir = getDefaultPromptWorkspace(repoRoot);
|
|
649
|
+
const configured =
|
|
650
|
+
configData && typeof configData.agentPrompts === "object"
|
|
651
|
+
? configData.agentPrompts
|
|
652
|
+
: {};
|
|
653
|
+
|
|
654
|
+
const prompts = {};
|
|
655
|
+
const sources = {};
|
|
656
|
+
|
|
657
|
+
for (const def of AGENT_PROMPT_DEFINITIONS) {
|
|
658
|
+
const fallback = DEFAULT_PROMPTS[def.key] || "";
|
|
659
|
+
const envPath = process.env[def.envVar];
|
|
660
|
+
const configuredPath = configured?.[def.key];
|
|
661
|
+
|
|
662
|
+
const candidates = [
|
|
663
|
+
...asPathCandidates(envPath, configDir, repoRoot),
|
|
664
|
+
...asPathCandidates(configuredPath, configDir, repoRoot),
|
|
665
|
+
resolve(workspaceDir, def.filename),
|
|
666
|
+
];
|
|
667
|
+
|
|
668
|
+
const loaded = readTemplateFile(candidates);
|
|
669
|
+
prompts[def.key] = loaded?.content || fallback;
|
|
670
|
+
sources[def.key] = {
|
|
671
|
+
source: loaded
|
|
672
|
+
? envPath
|
|
673
|
+
? "env"
|
|
674
|
+
: configuredPath
|
|
675
|
+
? "config"
|
|
676
|
+
: "workspace"
|
|
677
|
+
: "builtin",
|
|
678
|
+
path: loaded?.path || null,
|
|
679
|
+
envVar: def.envVar,
|
|
680
|
+
filename: def.filename,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
return {
|
|
685
|
+
prompts,
|
|
686
|
+
sources,
|
|
687
|
+
workspaceDir,
|
|
688
|
+
};
|
|
689
|
+
}
|