@lmctl-ai/lmctl 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.
Files changed (29) hide show
  1. package/LICENSE +36 -0
  2. package/README.md +36 -0
  3. package/bin/lmctl +4 -0
  4. package/dist/cli/index.js +2180 -0
  5. package/dist/cli/schema.sql +660 -0
  6. package/dist/cli/side_effect_classifier.json +19 -0
  7. package/dist/config/ai_test_templates/example-test.md.template +50 -0
  8. package/dist/config/ai_test_templates/index.md.template +27 -0
  9. package/dist/config/durable_memory_templates/index.md.template +29 -0
  10. package/dist/config/durable_memory_templates/skills_general.md.template +42 -0
  11. package/dist/config/durable_memory_templates/skills_lmdebug.md.template +31 -0
  12. package/dist/config/durable_memory_templates/skills_lmprobe.md.template +31 -0
  13. package/package.json +42 -0
  14. package/workflows/bugfix-extended-v2.compound.json +1018 -0
  15. package/workflows/bugfix-v2.compound.json +856 -0
  16. package/workflows/claim-check-spike-v2.compound.json +136 -0
  17. package/workflows/document-creation.compound.json +200 -0
  18. package/workflows/durable-memory-consolidation-v2.compound.json +185 -0
  19. package/workflows/example-v2.compound.json +200 -0
  20. package/workflows/image-qa.compound.json +128 -0
  21. package/workflows/index.jsonl +15 -0
  22. package/workflows/info-qa.compound.json +120 -0
  23. package/workflows/newspaper.compound.json +129 -0
  24. package/workflows/pr-fix.compound.json +183 -0
  25. package/workflows/pr-followup-v2.compound.json +969 -0
  26. package/workflows/provider-probe.compound.json +107 -0
  27. package/workflows/qa-suite.compound.json +186 -0
  28. package/workflows/spec-driven-task.compound.json +460 -0
  29. package/workflows/triage-v2.compound.json +721 -0
@@ -0,0 +1,721 @@
1
+ {
2
+ "schema_version": "lmctl/v3",
3
+ "definition_schema_version": 3,
4
+ "name": "triage-v2",
5
+ "version": 1,
6
+ "description": "Triages incoming issues, filters duplicates or unclear reports, assesses fixability, and produces candidate work items.",
7
+ "estimated_duration_ms": 60000,
8
+ "default_task_timeout_ms": 1800000,
9
+ "steps": [
10
+ {
11
+ "id": "s-list-open-bug-issues-6cd1",
12
+ "name": "list_open_bug_issues",
13
+ "type": "lmctl/review",
14
+ "typeVersion": 1,
15
+ "parameters": {
16
+ "max_loops": 5
17
+ },
18
+ "members": {
19
+ "coder": {
20
+ "team": "default",
21
+ "alias": "Triager",
22
+ "prompt_template": "List open bug issues for {{project.owner}}/{{project.repo}} (job payload: {{job_payload}}).\n\nFirst try label-aware:\n gh issue list --repo {{project.owner}}/{{project.repo}} --state open --label bug --limit 50 --json number,title,url,labels,assignees,createdAt,updatedAt,author,comments\nIf the repo does not use 'bug' label, fall back to a search query:\n gh issue list --repo {{project.owner}}/{{project.repo}} --state open --search 'created:>=<since_days_ago> bug OR crash OR panic OR regression OR fails' --limit 50 --json ...\n\nUse the job_payload.since_days (default 2), .max_issues (default 50), and .labels (default ['bug']) if set.\n\nSave the raw JSON list to /tmp/lmctl-next-run-{{run_id}}-issue-list.json. Print a short numbered summary (issue # + title + URL).\n\nSTANCE: issues_found | empty | gh_unavailable | failed"
23
+ }
24
+ }
25
+ },
26
+ {
27
+ "id": "s-fetch-issue-bodies-492d",
28
+ "name": "fetch_issue_bodies",
29
+ "type": "lmctl/review",
30
+ "typeVersion": 1,
31
+ "parameters": {
32
+ "max_loops": 5
33
+ },
34
+ "members": {
35
+ "coder": {
36
+ "team": "default",
37
+ "alias": "Triager",
38
+ "prompt_template": "For each issue URL in /tmp/lmctl-next-run-{{run_id}}-issue-list.json, fetch its body + comments:\n gh issue view <N> --repo {{project.owner}}/{{project.repo}} --json number,title,url,state,body,labels,assignees,author,comments,createdAt,updatedAt\n\nAggregate to /tmp/lmctl-next-run-{{run_id}}-issue-details.json (one entry per issue).\n\nIf at least one fetched successfully but some failed, return `partial`. If all failed, return `fetch_failed`.\n\nSTANCE: details_ready | partial | fetch_failed"
39
+ }
40
+ }
41
+ },
42
+ {
43
+ "id": "s-filter-non-bugs-5a56",
44
+ "name": "filter_non_bugs",
45
+ "type": "lmctl/review",
46
+ "typeVersion": 1,
47
+ "parameters": {
48
+ "max_loops": 5
49
+ },
50
+ "members": {
51
+ "coder": {
52
+ "team": "default",
53
+ "alias": "Triager",
54
+ "prompt_template": "Read /tmp/lmctl-next-run-{{run_id}}-issue-details.json. For each issue, classify `kept` vs `dropped`.\n\nDeterministic drops (don't waste budget on agent classification):\n- labels include any of: enhancement, feature, feature-request, question, discussion, docs, documentation, help-wanted (when standalone), wontfix, invalid\n- title or body explicitly says 'feature request', 'support question', 'how do I', 'discussion'\n\nKept criteria (agent body-read for ambiguous):\n- describes incorrect behavior, crash, regression, data loss, test failure, or API inconsistency\n- has expected vs actual behavior, repro snippet, stack trace, failing command, or enough code pointers\n- not a pure feature request, open-ended design discussion, support question, dependency upgrade, or vague complaint\n\nEmit /tmp/lmctl-next-run-{{run_id}}-filtered.json with per-issue: `{ url, kept: true|false, reason, confidence: 0..1, evidence: \"short body excerpt\" }`.\n\nIf you cannot classify >50% of issues, return `needs_human`.\n\nSTANCE: kept_some | none_kept | needs_human"
55
+ }
56
+ }
57
+ },
58
+ {
59
+ "id": "s-open-unassigned-unclaimed-1cb7",
60
+ "name": "open_unassigned_unclaimed",
61
+ "type": "lmctl/review",
62
+ "typeVersion": 1,
63
+ "parameters": {
64
+ "max_loops": 5
65
+ },
66
+ "members": {
67
+ "coder": {
68
+ "team": "default",
69
+ "alias": "Triager",
70
+ "prompt_template": "For each kept issue from /tmp/lmctl-next-run-{{run_id}}-filtered.json, check claim signals using the data already in /tmp/lmctl-next-run-{{run_id}}-issue-details.json:\n\nMark per issue:\n- `open_unclaimed`: state open, no assignees, no linked open PR, no maintainer 'I'll take this' / 'working on it' / 'assigned to me', no recent active claim from a contributor\n- `assigned`: has assignees\n- `claimed`: maintainer/contributor comment indicates active work\n- `closed`: state is closed (sanity check)\n- `needs_human`: signals conflict (e.g. assigned but assignee says 'help wanted')\n\nEmit /tmp/lmctl-next-run-{{run_id}}-claim-check.json.\n\nSTANCE: unclaimed_some | all_claimed | needs_human"
71
+ }
72
+ }
73
+ },
74
+ {
75
+ "id": "s-dedupe-794a",
76
+ "name": "dedupe",
77
+ "type": "lmctl/review",
78
+ "typeVersion": 1,
79
+ "parameters": {
80
+ "max_loops": 5
81
+ },
82
+ "members": {
83
+ "coder": {
84
+ "team": "default",
85
+ "alias": "Triager",
86
+ "prompt_template": "For each `open_unclaimed` issue from /tmp/lmctl-next-run-{{run_id}}-claim-check.json, run lmdedup:\n lmdedup --repo {{project.owner}}/{{project.repo}} --issue-url <ISSUE_URL> --json\n\nNotes:\n- GITHUB_TOKEN must be set; lmdedup also needs 30+ min timeout for large corpora — use `timeout 1800 lmdedup ...` if your shell respects it.\n- Save each per-issue lmdedup JSON to /tmp/lmctl-next-run-{{run_id}}-lmdedup-<issue_number>.json.\n\nAggregate to /tmp/lmctl-next-run-{{run_id}}-dedupe.json with per issue: `{ url, dedupe_outcome: distinct|duplicate|active_pr_exists|ambiguous, evidence }`.\n\nSTANCE: dedupe_done | dedupe_failed"
87
+ }
88
+ }
89
+ },
90
+ {
91
+ "id": "s-repro-clarity-c5ca",
92
+ "name": "repro_clarity",
93
+ "type": "lmctl/review",
94
+ "typeVersion": 1,
95
+ "parameters": {
96
+ "max_loops": 5
97
+ },
98
+ "members": {
99
+ "coder": {
100
+ "team": "default",
101
+ "alias": "Triager",
102
+ "prompt_template": "For each `distinct` issue from /tmp/lmctl-next-run-{{run_id}}-dedupe.json, score repro clarity from the body in /tmp/lmctl-next-run-{{run_id}}-issue-details.json:\n\n- 5: exact repro command/test/case\n- 4: clear code path + expected/actual\n- 3: enough detail for a repo expert to reproduce\n- 2: plausible but missing setup\n- 1: vague\n- 0: not reproducible from report\n\nClassification:\n- score >= 3 → `clear`\n- score == 2 → `needs_human`\n- score < 2 → `unclear` (will be skipped downstream)\n\nEmit /tmp/lmctl-next-run-{{run_id}}-repro-clarity.json.\n\nSTANCE: scored | needs_human"
103
+ }
104
+ }
105
+ },
106
+ {
107
+ "id": "s-fix-locality-and-test-availability-11a0",
108
+ "name": "fix_locality_and_test_availability",
109
+ "type": "lmctl/review",
110
+ "typeVersion": 1,
111
+ "parameters": {
112
+ "writes_to_project_path": true,
113
+ "max_loops": 5
114
+ },
115
+ "members": {
116
+ "coder": {
117
+ "team": "default",
118
+ "alias": "Coder",
119
+ "prompt_template": "`cd {{project.local_path}}` first. If that directory does not contain a checkout of {{project.owner}}/{{project.repo}}, `git clone https://github.com/{{project.owner}}/{{project.repo}}.git {{project.local_path}}` first.\n\nFor each `clear`-scored issue from /tmp/lmctl-next-run-{{run_id}}-repro-clarity.json:\n- read the body from /tmp/lmctl-next-run-{{run_id}}-issue-details.json\n- inspect likely files via `rg`/`grep`/`cat` (do NOT edit)\n- identify suspected touchpoints (file + approximate line)\n- identify the test framework and likely focused test command\n- do NOT run a full build\n\nEmit /tmp/lmctl-next-run-{{run_id}}-fixability.json per issue: `{ url, likely_files: [..], test_command: \"npm test\" | \"go test ./...\" | ..., risk: \"low|medium|high\", estimated_size: \"small|medium|large\", notes }`.\n\nClassification:\n- file pointers identified + test command found → `local_and_testable`\n- file pointers identified but tests unclear → `local_but_tests_unclear`\n- broad/risky scope → `broad_or_risky`\n- ambiguous → `needs_human`\n\nSTANCE: assessed | needs_human"
120
+ }
121
+ }
122
+ },
123
+ {
124
+ "id": "s-local-clone-toolchain-check-2388",
125
+ "name": "local_clone_toolchain_check",
126
+ "type": "lmctl/review",
127
+ "typeVersion": 1,
128
+ "parameters": {
129
+ "max_loops": 5
130
+ },
131
+ "members": {
132
+ "coder": {
133
+ "team": "default",
134
+ "alias": "Coder",
135
+ "prompt_template": "`cd {{project.local_path}}` first.\n\nVerify:\n1. Git checkout exists (`git rev-parse --is-inside-work-tree` returns true).\n2. Worktree is clean enough for branching (`git status --short` empty, unless job_payload.allow_existing_clone_dirty=true).\n3. Toolchain present for the test_command identified in fix_locality_and_test_availability — try `node --version`, `go version`, `python --version`, `cargo --version`, etc. as appropriate.\n\nDo NOT run a full build.\n\nSTANCE: ready | missing_clone | dirty_worktree | toolchain_missing | needs_human"
136
+ }
137
+ }
138
+ },
139
+ {
140
+ "id": "s-mark-33ff",
141
+ "name": "mark",
142
+ "type": "lmctl/review",
143
+ "typeVersion": 1,
144
+ "parameters": {
145
+ "max_loops": 5
146
+ },
147
+ "members": {
148
+ "coder": {
149
+ "team": "default",
150
+ "alias": "Triager",
151
+ "prompt_template": "Reduce all prior per-issue artifacts into a single triage_results.json.\n\nFor each issue from /tmp/lmctl-next-run-{{run_id}}-issue-details.json:\n- Join filtered.json + claim-check.json + dedupe.json + repro-clarity.json + fixability.json.\n- Status mapping:\n - `candidate`: kept + open_unclaimed + distinct + repro >= 3 + (local_and_testable or local_but_tests_unclear)\n - `assigned`: assignees present OR maintainer claim\n - `dup`: duplicate OR active_pr_exists\n - `skip`: non-bug OR repro < 2 OR broad_or_risky OR closed\n - `needs_human`: ambiguous dup OR repro == 2 OR conflicting signals\n\nWrite the final aggregate to /tmp/lmctl-next-run-{{run_id}}-triage_results.json (NOT inside {{project.local_path}} — triage MUST NOT dirty the target repo checkout).\n\nReturn STANCE: candidates_found (>=1 candidate), empty (no candidates), or needs_operator_review (mixed signals)."
152
+ }
153
+ }
154
+ },
155
+ {
156
+ "id": "s-assert-repo-clean-e754",
157
+ "name": "assert_repo_clean",
158
+ "type": "lmctl/shell-step",
159
+ "typeVersion": 1,
160
+ "parameters": {
161
+ "command": "test -z \"$(git -C {{project.local_path}} status --short)\"",
162
+ "outcomes_from_exit": {
163
+ "0": "@terminal:exit_0",
164
+ "default": "@terminal:exit_default"
165
+ }
166
+ }
167
+ },
168
+ {
169
+ "id": "s-operator-review-candidates-gate-596f",
170
+ "name": "operator_review_candidates_gate",
171
+ "type": "lmctl/interactive",
172
+ "typeVersion": 1,
173
+ "parameters": {
174
+ "termination": {
175
+ "operator_signal": true,
176
+ "max_turns": 1
177
+ }
178
+ },
179
+ "members": {
180
+ "agent": {
181
+ "team": "default",
182
+ "alias": "Triager",
183
+ "initial_prompt_template": "Triage produced candidates. Review /tmp/lmctl-next-run-{{run_id}}-triage_results.json (run artifact area; the target repo at {{project.local_path}} is left clean). Choose: approve_selected (write /tmp/lmctl-next-run-{{run_id}}-approved.json listing issue URLs to fix), approve_all_candidates (all status=candidate), reject_all, or needs_more_triage. Signal done when decided."
184
+ }
185
+ }
186
+ },
187
+ {
188
+ "id": "s-operator-review-candidates-decide-90a2",
189
+ "name": "operator_review_candidates_decide",
190
+ "type": "lmctl/review",
191
+ "typeVersion": 1,
192
+ "parameters": {
193
+ "max_loops": 5
194
+ },
195
+ "members": {
196
+ "coder": {
197
+ "team": "default",
198
+ "alias": "Triager",
199
+ "prompt_template": "The operator has reviewed the triage candidates. Based on the conversation context, determine their decision.\n\nIf the operator approved selected issues (wrote /tmp/lmctl-next-run-{{run_id}}-approved.json): STANCE: approve_selected\nIf the operator approved all candidates: STANCE: approve_all_candidates\nIf the operator rejected all: STANCE: reject_all\nIf the operator wants more triage: STANCE: needs_more_triage"
200
+ }
201
+ }
202
+ },
203
+ {
204
+ "id": "s-enqueue-fix-jobs-1d1d",
205
+ "name": "enqueue_fix_jobs",
206
+ "type": "lmctl/review",
207
+ "typeVersion": 1,
208
+ "parameters": {
209
+ "max_loops": 5
210
+ },
211
+ "members": {
212
+ "coder": {
213
+ "team": "default",
214
+ "alias": "Triager",
215
+ "prompt_template": "Operator outcome: {{outcomes.operator_review_candidates_decide}}.\n\nDetermine the approved issue URL set:\n- If outcome was `approve_all_candidates`: take every issue with status `candidate` from /tmp/lmctl-next-run-{{run_id}}-triage_results.json.\n- If outcome was `approve_selected`: read /tmp/lmctl-next-run-{{run_id}}-approved.json (operator-written list of URLs).\n\nFor each approved URL, enqueue a bugfix-pr-fixer job. The engine parses fenced ```spawn_jobs``` blocks from your reply — emit ONE such block containing a JSON array, one entry per approved URL:\n\n```spawn_jobs\n[\n {\"project_id\": {{project.id}}, \"payload\": {\"issue_url\": \"<URL1>\"}},\n {\"project_id\": {{project.id}}, \"payload\": {\"issue_url\": \"<URL2>\"}}\n]\n```\n\nIf no URLs are approved, return STANCE: nothing_to_enqueue and emit no spawn_jobs block.\nOn success, STANCE: enqueued.\nOn parse/IO failure, STANCE: failed."
216
+ }
217
+ }
218
+ },
219
+ {
220
+ "id": "s-terminal-aborted-3149",
221
+ "name": "terminal:aborted",
222
+ "type": "lmctl/terminal",
223
+ "typeVersion": 1,
224
+ "parameters": {
225
+ "name": "aborted",
226
+ "kind": "failure"
227
+ }
228
+ },
229
+ {
230
+ "id": "s-terminal-triage-empty-b170",
231
+ "name": "terminal:triage_empty",
232
+ "type": "lmctl/terminal",
233
+ "typeVersion": 1,
234
+ "parameters": {
235
+ "name": "triage_empty",
236
+ "kind": "neutral"
237
+ }
238
+ },
239
+ {
240
+ "id": "s-terminal-triage-complete-070a",
241
+ "name": "terminal:triage_complete",
242
+ "type": "lmctl/terminal",
243
+ "typeVersion": 1,
244
+ "parameters": {
245
+ "name": "triage_complete",
246
+ "kind": "success"
247
+ }
248
+ },
249
+ {
250
+ "id": "s-terminal-triage-partial-7311",
251
+ "name": "terminal:triage_partial",
252
+ "type": "lmctl/terminal",
253
+ "typeVersion": 1,
254
+ "parameters": {
255
+ "name": "triage_partial",
256
+ "kind": "neutral"
257
+ }
258
+ }
259
+ ],
260
+ "connections": {
261
+ "s-list-open-bug-issues-6cd1": {
262
+ "approve": [
263
+ [
264
+ {
265
+ "step_id": "s-terminal-aborted-3149",
266
+ "type": "main",
267
+ "index": 0
268
+ }
269
+ ]
270
+ ],
271
+ "issues_found": [
272
+ [
273
+ {
274
+ "step_id": "s-fetch-issue-bodies-492d",
275
+ "type": "main",
276
+ "index": 0
277
+ }
278
+ ]
279
+ ],
280
+ "empty": [
281
+ [
282
+ {
283
+ "step_id": "s-terminal-triage-empty-b170",
284
+ "type": "main",
285
+ "index": 0
286
+ }
287
+ ]
288
+ ],
289
+ "gh_unavailable": [
290
+ [
291
+ {
292
+ "step_id": "s-terminal-aborted-3149",
293
+ "type": "main",
294
+ "index": 0
295
+ }
296
+ ]
297
+ ],
298
+ "failed": [
299
+ [
300
+ {
301
+ "step_id": "s-terminal-aborted-3149",
302
+ "type": "main",
303
+ "index": 0
304
+ }
305
+ ]
306
+ ]
307
+ },
308
+ "s-fetch-issue-bodies-492d": {
309
+ "approve": [
310
+ [
311
+ {
312
+ "step_id": "s-terminal-aborted-3149",
313
+ "type": "main",
314
+ "index": 0
315
+ }
316
+ ]
317
+ ],
318
+ "details_ready": [
319
+ [
320
+ {
321
+ "step_id": "s-filter-non-bugs-5a56",
322
+ "type": "main",
323
+ "index": 0
324
+ }
325
+ ]
326
+ ],
327
+ "partial": [
328
+ [
329
+ {
330
+ "step_id": "s-filter-non-bugs-5a56",
331
+ "type": "main",
332
+ "index": 0
333
+ }
334
+ ]
335
+ ],
336
+ "fetch_failed": [
337
+ [
338
+ {
339
+ "step_id": "s-terminal-aborted-3149",
340
+ "type": "main",
341
+ "index": 0
342
+ }
343
+ ]
344
+ ]
345
+ },
346
+ "s-filter-non-bugs-5a56": {
347
+ "approve": [
348
+ [
349
+ {
350
+ "step_id": "s-terminal-aborted-3149",
351
+ "type": "main",
352
+ "index": 0
353
+ }
354
+ ]
355
+ ],
356
+ "kept_some": [
357
+ [
358
+ {
359
+ "step_id": "s-open-unassigned-unclaimed-1cb7",
360
+ "type": "main",
361
+ "index": 0
362
+ }
363
+ ]
364
+ ],
365
+ "none_kept": [
366
+ [
367
+ {
368
+ "step_id": "s-terminal-triage-empty-b170",
369
+ "type": "main",
370
+ "index": 0
371
+ }
372
+ ]
373
+ ],
374
+ "needs_human": [
375
+ [
376
+ {
377
+ "step_id": "s-open-unassigned-unclaimed-1cb7",
378
+ "type": "main",
379
+ "index": 0
380
+ }
381
+ ]
382
+ ]
383
+ },
384
+ "s-open-unassigned-unclaimed-1cb7": {
385
+ "approve": [
386
+ [
387
+ {
388
+ "step_id": "s-terminal-aborted-3149",
389
+ "type": "main",
390
+ "index": 0
391
+ }
392
+ ]
393
+ ],
394
+ "unclaimed_some": [
395
+ [
396
+ {
397
+ "step_id": "s-dedupe-794a",
398
+ "type": "main",
399
+ "index": 0
400
+ }
401
+ ]
402
+ ],
403
+ "all_claimed": [
404
+ [
405
+ {
406
+ "step_id": "s-terminal-triage-empty-b170",
407
+ "type": "main",
408
+ "index": 0
409
+ }
410
+ ]
411
+ ],
412
+ "needs_human": [
413
+ [
414
+ {
415
+ "step_id": "s-dedupe-794a",
416
+ "type": "main",
417
+ "index": 0
418
+ }
419
+ ]
420
+ ]
421
+ },
422
+ "s-dedupe-794a": {
423
+ "approve": [
424
+ [
425
+ {
426
+ "step_id": "s-terminal-aborted-3149",
427
+ "type": "main",
428
+ "index": 0
429
+ }
430
+ ]
431
+ ],
432
+ "dedupe_done": [
433
+ [
434
+ {
435
+ "step_id": "s-repro-clarity-c5ca",
436
+ "type": "main",
437
+ "index": 0
438
+ }
439
+ ]
440
+ ],
441
+ "dedupe_failed": [
442
+ [
443
+ {
444
+ "step_id": "s-terminal-aborted-3149",
445
+ "type": "main",
446
+ "index": 0
447
+ }
448
+ ]
449
+ ]
450
+ },
451
+ "s-repro-clarity-c5ca": {
452
+ "approve": [
453
+ [
454
+ {
455
+ "step_id": "s-terminal-aborted-3149",
456
+ "type": "main",
457
+ "index": 0
458
+ }
459
+ ]
460
+ ],
461
+ "scored": [
462
+ [
463
+ {
464
+ "step_id": "s-fix-locality-and-test-availability-11a0",
465
+ "type": "main",
466
+ "index": 0
467
+ }
468
+ ]
469
+ ],
470
+ "needs_human": [
471
+ [
472
+ {
473
+ "step_id": "s-fix-locality-and-test-availability-11a0",
474
+ "type": "main",
475
+ "index": 0
476
+ }
477
+ ]
478
+ ]
479
+ },
480
+ "s-fix-locality-and-test-availability-11a0": {
481
+ "approve": [
482
+ [
483
+ {
484
+ "step_id": "s-terminal-aborted-3149",
485
+ "type": "main",
486
+ "index": 0
487
+ }
488
+ ]
489
+ ],
490
+ "assessed": [
491
+ [
492
+ {
493
+ "step_id": "s-local-clone-toolchain-check-2388",
494
+ "type": "main",
495
+ "index": 0
496
+ }
497
+ ]
498
+ ],
499
+ "needs_human": [
500
+ [
501
+ {
502
+ "step_id": "s-local-clone-toolchain-check-2388",
503
+ "type": "main",
504
+ "index": 0
505
+ }
506
+ ]
507
+ ]
508
+ },
509
+ "s-local-clone-toolchain-check-2388": {
510
+ "approve": [
511
+ [
512
+ {
513
+ "step_id": "s-terminal-aborted-3149",
514
+ "type": "main",
515
+ "index": 0
516
+ }
517
+ ]
518
+ ],
519
+ "ready": [
520
+ [
521
+ {
522
+ "step_id": "s-mark-33ff",
523
+ "type": "main",
524
+ "index": 0
525
+ }
526
+ ]
527
+ ],
528
+ "missing_clone": [
529
+ [
530
+ {
531
+ "step_id": "s-terminal-aborted-3149",
532
+ "type": "main",
533
+ "index": 0
534
+ }
535
+ ]
536
+ ],
537
+ "dirty_worktree": [
538
+ [
539
+ {
540
+ "step_id": "s-terminal-aborted-3149",
541
+ "type": "main",
542
+ "index": 0
543
+ }
544
+ ]
545
+ ],
546
+ "toolchain_missing": [
547
+ [
548
+ {
549
+ "step_id": "s-terminal-aborted-3149",
550
+ "type": "main",
551
+ "index": 0
552
+ }
553
+ ]
554
+ ],
555
+ "needs_human": [
556
+ [
557
+ {
558
+ "step_id": "s-mark-33ff",
559
+ "type": "main",
560
+ "index": 0
561
+ }
562
+ ]
563
+ ]
564
+ },
565
+ "s-mark-33ff": {
566
+ "approve": [
567
+ [
568
+ {
569
+ "step_id": "s-terminal-aborted-3149",
570
+ "type": "main",
571
+ "index": 0
572
+ }
573
+ ]
574
+ ],
575
+ "candidates_found": [
576
+ [
577
+ {
578
+ "step_id": "s-assert-repo-clean-e754",
579
+ "type": "main",
580
+ "index": 0
581
+ }
582
+ ]
583
+ ],
584
+ "empty": [
585
+ [
586
+ {
587
+ "step_id": "s-terminal-triage-empty-b170",
588
+ "type": "main",
589
+ "index": 0
590
+ }
591
+ ]
592
+ ],
593
+ "needs_operator_review": [
594
+ [
595
+ {
596
+ "step_id": "s-assert-repo-clean-e754",
597
+ "type": "main",
598
+ "index": 0
599
+ }
600
+ ]
601
+ ]
602
+ },
603
+ "s-assert-repo-clean-e754": {
604
+ "exit_0": [
605
+ [
606
+ {
607
+ "step_id": "s-operator-review-candidates-gate-596f",
608
+ "type": "main",
609
+ "index": 0
610
+ }
611
+ ]
612
+ ],
613
+ "exit_default": [
614
+ [
615
+ {
616
+ "step_id": "s-terminal-aborted-3149",
617
+ "type": "main",
618
+ "index": 0
619
+ }
620
+ ]
621
+ ]
622
+ },
623
+ "s-operator-review-candidates-gate-596f": {
624
+ "done": [
625
+ [
626
+ {
627
+ "step_id": "s-operator-review-candidates-decide-90a2",
628
+ "type": "main",
629
+ "index": 0
630
+ }
631
+ ]
632
+ ]
633
+ },
634
+ "s-operator-review-candidates-decide-90a2": {
635
+ "approve": [
636
+ [
637
+ {
638
+ "step_id": "s-terminal-aborted-3149",
639
+ "type": "main",
640
+ "index": 0
641
+ }
642
+ ]
643
+ ],
644
+ "approve_selected": [
645
+ [
646
+ {
647
+ "step_id": "s-enqueue-fix-jobs-1d1d",
648
+ "type": "main",
649
+ "index": 0
650
+ }
651
+ ]
652
+ ],
653
+ "approve_all_candidates": [
654
+ [
655
+ {
656
+ "step_id": "s-enqueue-fix-jobs-1d1d",
657
+ "type": "main",
658
+ "index": 0
659
+ }
660
+ ]
661
+ ],
662
+ "reject_all": [
663
+ [
664
+ {
665
+ "step_id": "s-terminal-triage-complete-070a",
666
+ "type": "main",
667
+ "index": 0
668
+ }
669
+ ]
670
+ ],
671
+ "needs_more_triage": [
672
+ [
673
+ {
674
+ "step_id": "s-terminal-triage-partial-7311",
675
+ "type": "main",
676
+ "index": 0
677
+ }
678
+ ]
679
+ ]
680
+ },
681
+ "s-enqueue-fix-jobs-1d1d": {
682
+ "approve": [
683
+ [
684
+ {
685
+ "step_id": "s-terminal-aborted-3149",
686
+ "type": "main",
687
+ "index": 0
688
+ }
689
+ ]
690
+ ],
691
+ "enqueued": [
692
+ [
693
+ {
694
+ "step_id": "s-terminal-triage-complete-070a",
695
+ "type": "main",
696
+ "index": 0
697
+ }
698
+ ]
699
+ ],
700
+ "nothing_to_enqueue": [
701
+ [
702
+ {
703
+ "step_id": "s-terminal-triage-complete-070a",
704
+ "type": "main",
705
+ "index": 0
706
+ }
707
+ ]
708
+ ],
709
+ "failed": [
710
+ [
711
+ {
712
+ "step_id": "s-terminal-aborted-3149",
713
+ "type": "main",
714
+ "index": 0
715
+ }
716
+ ]
717
+ ]
718
+ }
719
+ },
720
+ "entry_step_id": "s-list-open-bug-issues-6cd1"
721
+ }