agentic-dev 0.2.1 → 0.2.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.
- package/.claude/skills/sdd/SKILL.md +178 -7
- package/.claude/skills/sdd/agents/openai.yaml +4 -0
- package/.claude/skills/sdd/references/section-map.md +67 -0
- package/package.json +1 -1
- package/sdd/99_toolchain/01_automation/agentic-dev/run_repo_phase.sh +1 -1
- package/.claude/skills/commit/SKILL.md +0 -37
- package/.claude/skills/dev-browser/SKILL.md +0 -30
- package/.claude/skills/otro/SKILL.md +0 -43
- package/.claude/skills/planning-with-files/SKILL.md +0 -37
- package/.claude/skills/prd/SKILL.md +0 -27
- package/.claude/skills/ralph-loop/SKILL.md +0 -42
- package/.claude/skills/sdd-dev/SKILL.md +0 -71
- package/.claude/skills/sdd-development/SKILL.md +0 -13
- package/.codex/skills/agents/openai.yaml +0 -4
- package/.codex/skills/commit/SKILL.md +0 -219
- package/.codex/skills/commit/references/commit_examples.md +0 -292
- package/.codex/skills/dev-browser/SKILL.md +0 -211
- package/.codex/skills/dev-browser/bun.lock +0 -443
- package/.codex/skills/dev-browser/package-lock.json +0 -2988
- package/.codex/skills/dev-browser/package.json +0 -31
- package/.codex/skills/dev-browser/references/scraping.md +0 -155
- package/.codex/skills/dev-browser/scripts/start-relay.ts +0 -32
- package/.codex/skills/dev-browser/scripts/start-server.ts +0 -117
- package/.codex/skills/dev-browser/server.sh +0 -24
- package/.codex/skills/dev-browser/src/client.ts +0 -474
- package/.codex/skills/dev-browser/src/index.ts +0 -287
- package/.codex/skills/dev-browser/src/relay.ts +0 -731
- package/.codex/skills/dev-browser/src/snapshot/__tests__/snapshot.test.ts +0 -223
- package/.codex/skills/dev-browser/src/snapshot/browser-script.ts +0 -877
- package/.codex/skills/dev-browser/src/snapshot/index.ts +0 -14
- package/.codex/skills/dev-browser/src/snapshot/inject.ts +0 -13
- package/.codex/skills/dev-browser/src/types.ts +0 -34
- package/.codex/skills/dev-browser/tsconfig.json +0 -36
- package/.codex/skills/dev-browser/vitest.config.ts +0 -12
- package/.codex/skills/otro/SKILL.md +0 -74
- package/.codex/skills/otro/agents/openai.yaml +0 -4
- package/.codex/skills/otro/references/agent-prompts.md +0 -61
- package/.codex/skills/otro/references/contracts.md +0 -146
- package/.codex/skills/otro/references/orchestration-loop.md +0 -51
- package/.codex/skills/otro/references/runtime.md +0 -79
- package/.codex/skills/otro/runs/README.md +0 -11
- package/.codex/skills/otro/schemas/step_plan.schema.json +0 -289
- package/.codex/skills/otro/schemas/task_result.schema.json +0 -142
- package/.codex/skills/otro/schemas/wave_plan.schema.json +0 -4
- package/.codex/skills/otro/scripts/README.md +0 -38
- package/.codex/skills/otro/scripts/bump_validation_header.py +0 -179
- package/.codex/skills/otro/scripts/check_validation_header.py +0 -84
- package/.codex/skills/otro/scripts/common.py +0 -303
- package/.codex/skills/otro/scripts/init_run.sh +0 -68
- package/.codex/skills/otro/scripts/plan_loop.py +0 -8
- package/.codex/skills/otro/scripts/plan_step.py +0 -367
- package/.codex/skills/otro/scripts/plan_wave.py +0 -8
- package/.codex/skills/otro/scripts/reconcile_loop.py +0 -8
- package/.codex/skills/otro/scripts/reconcile_step.py +0 -37
- package/.codex/skills/otro/scripts/reconcile_wave.py +0 -8
- package/.codex/skills/otro/scripts/run_loop.py +0 -300
- package/.codex/skills/otro/scripts/run_loop_step.py +0 -8
- package/.codex/skills/otro/scripts/run_step.py +0 -246
- package/.codex/skills/otro/scripts/run_wave.py +0 -8
- package/.codex/skills/otro/validation/validation.md +0 -15
- package/.codex/skills/planning-with-files/SKILL.md +0 -42
- package/.codex/skills/planning-with-files/agents/openai.yaml +0 -4
- package/.codex/skills/planning-with-files/assets/plan-template.md +0 -37
- package/.codex/skills/planning-with-files/references/plan-rules.md +0 -35
- package/.codex/skills/planning-with-files/scripts/new_plan.sh +0 -65
- package/.codex/skills/prd/SKILL.md +0 -235
- package/.codex/skills/ralph-loop/SKILL.md +0 -46
- package/.codex/skills/ralph-loop/agents/openai.yaml +0 -4
- package/.codex/skills/ralph-loop/references/failure-triage.md +0 -32
- package/.codex/skills/ralph-loop/scripts/loop_until_success.sh +0 -97
- package/sdd/99_toolchain/02_policies/otro-orchestration-policy.md +0 -30
|
@@ -1,367 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
import json
|
|
6
|
-
from pathlib import Path
|
|
7
|
-
|
|
8
|
-
from common import (
|
|
9
|
-
anchor_plan_path,
|
|
10
|
-
canonicalize_plan,
|
|
11
|
-
ensure_anchor_plan,
|
|
12
|
-
load_json,
|
|
13
|
-
load_loop_results,
|
|
14
|
-
load_text,
|
|
15
|
-
plan_steps,
|
|
16
|
-
planner_timeout_seconds,
|
|
17
|
-
repo_root_from_run_dir,
|
|
18
|
-
run_codex_exec,
|
|
19
|
-
salvage_json_output,
|
|
20
|
-
skill_dir_from_file,
|
|
21
|
-
set_plan_steps,
|
|
22
|
-
set_task_step,
|
|
23
|
-
task_step,
|
|
24
|
-
write_json,
|
|
25
|
-
)
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def normalize_pending_loop_numbers(plan: dict) -> dict:
|
|
29
|
-
plan = canonicalize_plan(plan)
|
|
30
|
-
plan_version = int(plan["plan_version"])
|
|
31
|
-
pending_loops = sorted({task_step(task) for task in plan.get("tasks", []) if task.get("status") == "pending"})
|
|
32
|
-
if not pending_loops:
|
|
33
|
-
return plan
|
|
34
|
-
mapping = {old: plan_version + idx for idx, old in enumerate(pending_loops)}
|
|
35
|
-
if all(old == new for old, new in mapping.items()):
|
|
36
|
-
return plan
|
|
37
|
-
|
|
38
|
-
task_index = {task["id"]: task for task in plan.get("tasks", [])}
|
|
39
|
-
for task in plan.get("tasks", []):
|
|
40
|
-
if task.get("status") == "pending":
|
|
41
|
-
set_task_step(task, mapping[task_step(task)])
|
|
42
|
-
|
|
43
|
-
normalized_steps = []
|
|
44
|
-
for entry in plan_steps(plan):
|
|
45
|
-
item = dict(entry)
|
|
46
|
-
old_wave = int(item["step"])
|
|
47
|
-
pending_ids = [task_id for task_id in entry.get("task_ids", []) if task_index.get(task_id, {}).get("status") == "pending"]
|
|
48
|
-
if old_wave in mapping and pending_ids:
|
|
49
|
-
item["step"] = mapping[old_wave]
|
|
50
|
-
item["goal"] = str(item.get("goal", "")).replace(f"Wave {old_wave}", f"Loop {mapping[old_wave]}")
|
|
51
|
-
item["goal"] = str(item.get("goal", "")).replace(f"wave {old_wave}", f"loop {mapping[old_wave]}")
|
|
52
|
-
item["goal"] = str(item.get("goal", "")).replace(f"Step {old_wave}", f"Step {mapping[old_wave]}")
|
|
53
|
-
item["goal"] = str(item.get("goal", "")).replace(f"step {old_wave}", f"step {mapping[old_wave]}")
|
|
54
|
-
normalized_steps.append(item)
|
|
55
|
-
|
|
56
|
-
set_plan_steps(plan, sorted(normalized_steps, key=lambda item: int(item["step"])))
|
|
57
|
-
return plan
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
def split_timeout_followups(task: dict) -> list[dict]:
|
|
61
|
-
owned_paths = list(task.get("owned_paths", []))
|
|
62
|
-
read_paths = list(task.get("read_paths", []))
|
|
63
|
-
acceptance = list(task.get("acceptance_criteria", []))
|
|
64
|
-
verification = list(task.get("verification_commands", []))
|
|
65
|
-
|
|
66
|
-
def split_list(items: list[str]) -> tuple[list[str], list[str]]:
|
|
67
|
-
if not items:
|
|
68
|
-
return [], []
|
|
69
|
-
mid = max(1, len(items) // 2)
|
|
70
|
-
left = items[:mid]
|
|
71
|
-
right = items[mid:] or items[:1]
|
|
72
|
-
return left, right
|
|
73
|
-
|
|
74
|
-
owned_a, owned_b = split_list(owned_paths)
|
|
75
|
-
read_a, read_b = split_list(read_paths)
|
|
76
|
-
acc_a, acc_b = split_list(acceptance)
|
|
77
|
-
ver_a, ver_b = split_list(verification)
|
|
78
|
-
|
|
79
|
-
if not owned_a:
|
|
80
|
-
owned_a = owned_paths[:]
|
|
81
|
-
if not owned_b:
|
|
82
|
-
owned_b = owned_paths[:] if owned_paths else read_b[:]
|
|
83
|
-
if not read_a:
|
|
84
|
-
read_a = read_paths[:]
|
|
85
|
-
if not read_b:
|
|
86
|
-
read_b = read_paths[:] if read_paths else read_a[:]
|
|
87
|
-
|
|
88
|
-
return [
|
|
89
|
-
{
|
|
90
|
-
"title": f"{task['title']} [split-A]",
|
|
91
|
-
"kind": task["kind"],
|
|
92
|
-
"objective": (
|
|
93
|
-
f"Recover from timeout by completing the first narrowed half of `{task['title']}`. "
|
|
94
|
-
f"Focus only on these paths first: {', '.join(owned_a or read_a)}."
|
|
95
|
-
),
|
|
96
|
-
"owned_paths": owned_a,
|
|
97
|
-
"read_paths": read_a,
|
|
98
|
-
"acceptance_criteria": acc_a or acceptance,
|
|
99
|
-
"verification_commands": ver_a,
|
|
100
|
-
"reason": f"Automatic timeout split of {task['id']} into the first narrower subtask.",
|
|
101
|
-
},
|
|
102
|
-
{
|
|
103
|
-
"title": f"{task['title']} [split-B]",
|
|
104
|
-
"kind": task["kind"],
|
|
105
|
-
"objective": (
|
|
106
|
-
f"Recover from timeout by completing the second narrowed half of `{task['title']}`. "
|
|
107
|
-
f"Focus only on these paths after split-A stabilizes: {', '.join(owned_b or read_b)}."
|
|
108
|
-
),
|
|
109
|
-
"owned_paths": owned_b,
|
|
110
|
-
"read_paths": read_b,
|
|
111
|
-
"acceptance_criteria": acc_b or acceptance,
|
|
112
|
-
"verification_commands": ver_b,
|
|
113
|
-
"reason": f"Automatic timeout split of {task['id']} into the second narrower subtask.",
|
|
114
|
-
},
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
def compact_results_blob(results_payload: dict, current_plan: dict) -> str:
|
|
119
|
-
task_index = {task["id"]: task for task in current_plan.get("tasks", [])}
|
|
120
|
-
compact = {
|
|
121
|
-
"loop": results_payload.get("loop", results_payload.get("wave")),
|
|
122
|
-
"tasks": [],
|
|
123
|
-
}
|
|
124
|
-
for item in results_payload.get("tasks", []):
|
|
125
|
-
result = item.get("result", {})
|
|
126
|
-
source_task = task_index.get(item.get("task_id"), {})
|
|
127
|
-
timed_out = int(item.get("returncode", 0)) == 124
|
|
128
|
-
compact["tasks"].append(
|
|
129
|
-
{
|
|
130
|
-
"task_id": item.get("task_id"),
|
|
131
|
-
"returncode": item.get("returncode"),
|
|
132
|
-
"timed_out": timed_out,
|
|
133
|
-
"status": result.get("status"),
|
|
134
|
-
"summary": result.get("summary"),
|
|
135
|
-
"changed_files": result.get("changed_files", []),
|
|
136
|
-
"blockers": result.get("blockers", []),
|
|
137
|
-
"integration_notes": result.get("integration_notes", []),
|
|
138
|
-
"residual_signals": result.get("residual_signals", []),
|
|
139
|
-
"proposed_follow_up_tasks": result.get("proposed_follow_up_tasks", []),
|
|
140
|
-
"timeout_split_tasks": split_timeout_followups(source_task) if timed_out and source_task else [],
|
|
141
|
-
}
|
|
142
|
-
)
|
|
143
|
-
return json.dumps(compact, indent=2, ensure_ascii=False)
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
def build_initial_prompt(
|
|
147
|
-
run_name: str,
|
|
148
|
-
goal_text: str,
|
|
149
|
-
max_tasks: int,
|
|
150
|
-
plan_version: int,
|
|
151
|
-
run_dir_rel: str,
|
|
152
|
-
overlap_policy: str,
|
|
153
|
-
) -> str:
|
|
154
|
-
return f"""Use $otro.
|
|
155
|
-
|
|
156
|
-
You are producing a repository-wide refactoring plan for run `{run_name}`.
|
|
157
|
-
This workflow is not recursive depth-first delegation. It is:
|
|
158
|
-
1. Analyze the repository and the goal globally.
|
|
159
|
-
2. Produce an upfront TODO/task graph.
|
|
160
|
-
3. Group disjoint tasks into execution steps.
|
|
161
|
-
4. Reserve merge and integration work for later loops.
|
|
162
|
-
|
|
163
|
-
Requirements:
|
|
164
|
-
- Inspect the repository before answering.
|
|
165
|
-
- Use at most 12 shell commands before finalizing.
|
|
166
|
-
- Inspect only the paths needed to satisfy the stated repository-wide goal.
|
|
167
|
-
- Produce at most {max_tasks} tasks total in this plan version.
|
|
168
|
-
- The first execution loop should favor analysis, boundary clarification, inventory building, and low-conflict work.
|
|
169
|
-
- Overlap policy for this run: `{overlap_policy}`.
|
|
170
|
-
- If overlap policy is `strict`, keep `owned_paths` disjoint inside a loop.
|
|
171
|
-
- If overlap policy is `tolerant`, allow overlap where it improves exploration and add explicit residual/integration tasks for the next loop.
|
|
172
|
-
- Keep worker prompts concrete enough that a separate Codex process can execute the task.
|
|
173
|
-
- Fill `verification_commands` only with commands that are actually relevant.
|
|
174
|
-
- Use status `pending` for not-yet-run tasks.
|
|
175
|
-
- Emit `step` on every task and `steps` as the grouped frontier list. Do not use `wave`/`waves` in new output.
|
|
176
|
-
- Emit `anchor_alignment` with `status` and `notes`. For the initial plan, mark it `aligned`.
|
|
177
|
-
- Emit `completion_policy` with all of:
|
|
178
|
-
- `done_when`: short legacy summary mirroring repository completion
|
|
179
|
-
- `loop_done`: when the current plan backlog is exhausted
|
|
180
|
-
- `run_done`: when a fresh repository-wide rescan after loop_done yields no materially new tasks
|
|
181
|
-
- `repository_done`: when run_done and repository-level deployment/verification gates pass
|
|
182
|
-
- `replan_when`: conditions that should open the next OTRO plan or run
|
|
183
|
-
- Return one final JSON object only. Do not emit provisional JSON.
|
|
184
|
-
- Do not output partial plans, intermediate JSON, or command-budget narration.
|
|
185
|
-
- Finish repository inspection first, then emit a single consolidated plan that covers the full goal scope.
|
|
186
|
-
|
|
187
|
-
Planning guidance:
|
|
188
|
-
- Cover all major repository surfaces that matter to the stated goal.
|
|
189
|
-
- Prefer broad initial decomposition over narrow local optimization.
|
|
190
|
-
- Use later loops for integration or edit work after the analysis frontier is established.
|
|
191
|
-
- Favor coarse-grained tasks that partition the repository cleanly over many tiny tasks.
|
|
192
|
-
- Keep orchestration state run-local. Use `{run_dir_rel}/plans/current-plan.json` for the synthesized plan, and place run artifacts under `{run_dir_rel}/` unless the task is explicitly about repo-level production assets.
|
|
193
|
-
|
|
194
|
-
Run name: {run_name}
|
|
195
|
-
Plan version to emit: {plan_version}
|
|
196
|
-
Run directory: {run_dir_rel}
|
|
197
|
-
|
|
198
|
-
Goal file:
|
|
199
|
-
{goal_text}
|
|
200
|
-
"""
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
def build_replan_prompt(
|
|
204
|
-
run_name: str,
|
|
205
|
-
goal_text: str,
|
|
206
|
-
anchor_plan_text: str,
|
|
207
|
-
current_plan_text: str,
|
|
208
|
-
results_blob: str,
|
|
209
|
-
max_tasks: int,
|
|
210
|
-
plan_version: int,
|
|
211
|
-
finished_loop: int,
|
|
212
|
-
run_dir_rel: str,
|
|
213
|
-
overlap_policy: str,
|
|
214
|
-
) -> str:
|
|
215
|
-
return f"""Use $otro.
|
|
216
|
-
|
|
217
|
-
You are reconciling a repository-wide Codex orchestration run after loop {finished_loop} for `{run_name}`.
|
|
218
|
-
|
|
219
|
-
Workflow contract:
|
|
220
|
-
1. Read the goal.
|
|
221
|
-
2. Read the anchor plan from the first planning pass.
|
|
222
|
-
3. Read the current plan.
|
|
223
|
-
4. Read the completed task results.
|
|
224
|
-
5. Inspect the current repository state.
|
|
225
|
-
6. Emit the next plan version with updated statuses and next-loop tasks.
|
|
226
|
-
|
|
227
|
-
Rules:
|
|
228
|
-
- Use at most 12 shell commands before finalizing.
|
|
229
|
-
- Treat the anchor plan as the teacher prior for repository-wide intent, decomposition axes, and invariants.
|
|
230
|
-
- Preserve completed tasks in the task list and mark them `completed`, `blocked`, or `failed`.
|
|
231
|
-
- Emit `anchor_alignment` with `status` and `notes` explaining whether the live plan still matches the anchor plan.
|
|
232
|
-
- Keep `step` and `steps` as the canonical execution-slice fields. Do not emit new `wave`/`waves` keys.
|
|
233
|
-
- Emit `completion_policy` with all of:
|
|
234
|
-
- `done_when`: short legacy summary mirroring repository completion
|
|
235
|
-
- `loop_done`: when the current plan backlog is exhausted
|
|
236
|
-
- `run_done`: when a fresh repository-wide rescan after loop_done yields no materially new tasks
|
|
237
|
-
- `repository_done`: when run_done and repository-level deployment/verification gates pass
|
|
238
|
-
- `replan_when`: conditions that should open the next OTRO plan or run
|
|
239
|
-
- Add new tasks only when integration evidence requires them.
|
|
240
|
-
- Do not re-queue tasks that already succeeded unless integration broke their acceptance criteria.
|
|
241
|
-
- If a task timed out, do not re-run it unchanged. Replace it with exactly two narrower follow-up tasks derived from the timeout split hints or an equivalent two-way split.
|
|
242
|
-
- Keep at most {max_tasks} tasks in the emitted plan.
|
|
243
|
-
- Overlap policy for this run: `{overlap_policy}`.
|
|
244
|
-
- If overlap policy is `strict`, maintain disjoint `owned_paths` inside each pending loop.
|
|
245
|
-
- If overlap policy is `tolerant`, preserve useful overlap and express repair work through residual-driven follow-up tasks.
|
|
246
|
-
- Insert explicit integration tasks when cross-file reconciliation is needed.
|
|
247
|
-
- Return one final JSON object only. Do not emit provisional JSON.
|
|
248
|
-
- Do not output partial plans, intermediate JSON, or command-budget narration.
|
|
249
|
-
|
|
250
|
-
Replanning guidance:
|
|
251
|
-
- Keep the plan aligned with the repository-wide goal and the anchor plan rather than a single subsystem.
|
|
252
|
-
- Preserve successful work and only refine the graph where new evidence requires it.
|
|
253
|
-
- Prefer updating the existing task graph over replacing it wholesale.
|
|
254
|
-
- Do not let temporary overlap or a dirty intermediate repo state erase the original decomposition intent.
|
|
255
|
-
- If the current state materially diverges from the anchor plan, express that as explicit residual or repair tasks rather than silently drifting the plan.
|
|
256
|
-
- For timeouts, prefer scope reduction over retry. The next plan should shrink timed-out work into two smaller tasks, not repeat the same task verbatim.
|
|
257
|
-
- Keep orchestration state run-local. Use `{run_dir_rel}/plans/current-plan.json` for synthesized plan updates, and keep run artifacts under `{run_dir_rel}/` unless the task is explicitly about repo-level production assets.
|
|
258
|
-
|
|
259
|
-
Run name: {run_name}
|
|
260
|
-
Next plan version: {plan_version}
|
|
261
|
-
Finished loop: {finished_loop}
|
|
262
|
-
Run directory: {run_dir_rel}
|
|
263
|
-
|
|
264
|
-
Goal file:
|
|
265
|
-
{goal_text}
|
|
266
|
-
|
|
267
|
-
Anchor plan JSON:
|
|
268
|
-
{anchor_plan_text}
|
|
269
|
-
|
|
270
|
-
Current plan JSON:
|
|
271
|
-
{current_plan_text}
|
|
272
|
-
|
|
273
|
-
Loop results JSON:
|
|
274
|
-
{results_blob}
|
|
275
|
-
"""
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
def main() -> int:
|
|
279
|
-
parser = argparse.ArgumentParser()
|
|
280
|
-
parser.add_argument("run_dir")
|
|
281
|
-
parser.add_argument("--mode", choices=["initial", "replan"], default="initial")
|
|
282
|
-
parser.add_argument("--finished-loop", type=int)
|
|
283
|
-
parser.add_argument("--finished-wave", type=int)
|
|
284
|
-
args = parser.parse_args()
|
|
285
|
-
|
|
286
|
-
run_dir = Path(args.run_dir).resolve()
|
|
287
|
-
skill_dir = skill_dir_from_file(__file__)
|
|
288
|
-
repo_root = repo_root_from_run_dir(run_dir)
|
|
289
|
-
schema_path = skill_dir / "schemas" / "step_plan.schema.json"
|
|
290
|
-
config = load_json(run_dir / "config.json")
|
|
291
|
-
state = load_json(run_dir / "state.json")
|
|
292
|
-
goal_text = load_text(run_dir / "goal.md")
|
|
293
|
-
run_dir_rel = str(run_dir.relative_to(repo_root))
|
|
294
|
-
plan_version = int(state["plan_version"]) + 1
|
|
295
|
-
output_path = run_dir / "plans" / f"plan-v{plan_version}.json"
|
|
296
|
-
current_link = run_dir / "plans" / "current-plan.json"
|
|
297
|
-
log_path = run_dir / "logs" / f"plan-v{plan_version}.log"
|
|
298
|
-
|
|
299
|
-
max_tasks = int(config.get("max_tasks_total", config.get("max_tasks_per_step", config["max_tasks_per_wave"])))
|
|
300
|
-
overlap_policy = str(config.get("overlap_policy", "strict"))
|
|
301
|
-
|
|
302
|
-
if args.mode == "initial":
|
|
303
|
-
prompt = build_initial_prompt(
|
|
304
|
-
run_name=config["run_name"],
|
|
305
|
-
goal_text=goal_text,
|
|
306
|
-
max_tasks=max_tasks,
|
|
307
|
-
plan_version=plan_version,
|
|
308
|
-
run_dir_rel=run_dir_rel,
|
|
309
|
-
overlap_policy=overlap_policy,
|
|
310
|
-
)
|
|
311
|
-
else:
|
|
312
|
-
finished_loop = args.finished_loop if args.finished_loop is not None else args.finished_wave
|
|
313
|
-
if finished_loop is None:
|
|
314
|
-
raise SystemExit("--finished-loop is required in replan mode")
|
|
315
|
-
anchor_path = anchor_plan_path(run_dir)
|
|
316
|
-
if not anchor_path.exists():
|
|
317
|
-
fallback_plan = run_dir / "plans" / "plan-v1.json"
|
|
318
|
-
ensure_anchor_plan(run_dir, fallback_plan if fallback_plan.exists() else current_link)
|
|
319
|
-
anchor_plan_text = load_text(anchor_path)
|
|
320
|
-
current_plan_text = load_text(current_link)
|
|
321
|
-
results_payload = load_loop_results(run_dir, int(finished_loop))
|
|
322
|
-
results_blob = compact_results_blob(results_payload, load_json(current_link))
|
|
323
|
-
prompt = build_replan_prompt(
|
|
324
|
-
run_name=config["run_name"],
|
|
325
|
-
goal_text=goal_text,
|
|
326
|
-
anchor_plan_text=anchor_plan_text,
|
|
327
|
-
current_plan_text=current_plan_text,
|
|
328
|
-
results_blob=results_blob,
|
|
329
|
-
max_tasks=max_tasks,
|
|
330
|
-
plan_version=plan_version,
|
|
331
|
-
finished_loop=int(finished_loop),
|
|
332
|
-
run_dir_rel=run_dir_rel,
|
|
333
|
-
overlap_policy=overlap_policy,
|
|
334
|
-
)
|
|
335
|
-
|
|
336
|
-
result = run_codex_exec(
|
|
337
|
-
repo_root=repo_root,
|
|
338
|
-
prompt=prompt,
|
|
339
|
-
model=str(config["model"]),
|
|
340
|
-
schema_path=schema_path,
|
|
341
|
-
output_path=output_path,
|
|
342
|
-
log_path=log_path,
|
|
343
|
-
timeout_seconds=planner_timeout_seconds(config),
|
|
344
|
-
)
|
|
345
|
-
if not output_path.exists():
|
|
346
|
-
salvage_json_output(log_path, output_path)
|
|
347
|
-
elif output_path.stat().st_size == 0:
|
|
348
|
-
salvage_json_output(log_path, output_path)
|
|
349
|
-
if not output_path.exists() or result.returncode != 0 or output_path.stat().st_size == 0:
|
|
350
|
-
raise SystemExit(result.returncode)
|
|
351
|
-
|
|
352
|
-
plan_payload = canonicalize_plan(load_json(output_path))
|
|
353
|
-
plan_payload = normalize_pending_loop_numbers(plan_payload)
|
|
354
|
-
write_json(output_path, plan_payload)
|
|
355
|
-
|
|
356
|
-
state["plan_version"] = plan_version
|
|
357
|
-
state["current_loop"] = plan_version
|
|
358
|
-
state["current_step"] = plan_version
|
|
359
|
-
write_json(run_dir / "state.json", state)
|
|
360
|
-
current_link.write_text(load_text(output_path), encoding="utf-8")
|
|
361
|
-
if args.mode == "initial":
|
|
362
|
-
ensure_anchor_plan(run_dir, output_path)
|
|
363
|
-
return 0
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
if __name__ == "__main__":
|
|
367
|
-
raise SystemExit(main())
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
from __future__ import annotations
|
|
3
|
-
|
|
4
|
-
import argparse
|
|
5
|
-
from pathlib import Path
|
|
6
|
-
|
|
7
|
-
from common import load_loop_results
|
|
8
|
-
from plan_loop import main as plan_loop_main
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
def main() -> int:
|
|
12
|
-
parser = argparse.ArgumentParser()
|
|
13
|
-
parser.add_argument("run_dir")
|
|
14
|
-
parser.add_argument("--loop", type=int, help="Loop number to reconcile.")
|
|
15
|
-
parser.add_argument("--wave", type=int, help="Legacy alias for --loop.")
|
|
16
|
-
args = parser.parse_args()
|
|
17
|
-
loop_number = args.loop if args.loop is not None else args.wave
|
|
18
|
-
if loop_number is None:
|
|
19
|
-
raise SystemExit("--loop is required")
|
|
20
|
-
|
|
21
|
-
run_dir = Path(args.run_dir).resolve()
|
|
22
|
-
load_loop_results(run_dir, loop_number)
|
|
23
|
-
import sys
|
|
24
|
-
|
|
25
|
-
sys.argv = [
|
|
26
|
-
"plan_loop.py",
|
|
27
|
-
str(run_dir),
|
|
28
|
-
"--mode",
|
|
29
|
-
"replan",
|
|
30
|
-
"--finished-loop",
|
|
31
|
-
str(loop_number),
|
|
32
|
-
]
|
|
33
|
-
return plan_loop_main()
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
if __name__ == "__main__":
|
|
37
|
-
raise SystemExit(main())
|